定义一个变量

属性描述符(Property Descriptors)

var myObject = {
    a: 2
};

Object.getOwnPropertyDescriptor( myObject, "a" );
// {
//    value: 2,
//    writable: true,
//    enumerable: true,
//    configurable: true
// }

我们普通的对象属性a的属性描述符(称为“数据描述符”,因为它仅持有一个数据值)的内容要比value为2多得多。它还包含另外3个性质:writable,enumerable,和configurable。

可写性(Writable)

writable控制着你改变属性值的能力。

var myObject = {};

Object.defineProperty( myObject, "a", {
    value: 2,
    writable: false, // 不可写!
    configurable: true,
    enumerable: true
} );

myObject.a = 3;

myObject.a; // 2

我们对value的修改悄无声息地失败了

可配置性(Configurable)

只要属性当前是可配置的,我们就可以使用同样的defineProperty(..)工具,修改它的描述符定义。

var myObject = {
    a: 2
};

myObject.a = 3;
myObject.a;                    // 3

Object.defineProperty( myObject, "a", {
    value: 4,
    writable: true,
    configurable: false,    // 不可配置!
    enumerable: true
} );

myObject.a;                    // 4
myObject.a = 5;
myObject.a;                    // 5

Object.defineProperty( myObject, "a", {
    value: 6,
    writable: true,
    configurable: true,
    enumerable: true
} ); // TypeError

最后的defineProperty(..)调用导致了一个TypeError,这与strict mode无关,如果你试图改变一个不可配置属性的描述符定义,就会发生TypeError。要小心:如你所看到的,将configurable设置为false是 一个单向操作,不可撤销!

注意: 这里有一个需要注意的微小例外:即便属性已经是configurable:false,writable总是可以没有错误地从true改变为false,但如果已经是false的话不能变回true。

configurable:false阻止的另外一个事情是使用delete操作符移除既存属性的能力。

对象常量(Object Constant)

通过将writable:false与configurable:false组合,你可以实质上创建了一个作为对象属性的 常量(不能被改变,重定义或删除),比如:

var myObject = {};

Object.defineProperty( myObject, "FAVORITE_NUMBER", {
    value: 42,
    writable: false,
    configurable: false
} );

防止扩展(Prevent Extensions)

如果你想防止一个对象被添加新的属性,但另一方面保留其他既存的对象属性,调用Object.preventExtensions(..):

var myObject = {
    a: 2
};

Object.preventExtensions( myObject );

myObject.b = 3;
myObject.b; // undefined

封印(Seal)和 冻结(Freeze)

Object.seal(..)创建一个“封印”的对象,这意味着它实质上在当前的对象上调用Object.preventExtensions(..),同时也将它所有的既存属性标记为configurable:false。
所以,你既不能添加更多的属性,也不能重新配置或删除既存属性(虽然你依然 可以 修改它们的值)。

Object.freeze(..)创建一个冻结的对象,这意味着它实质上在当前的对象上调用Object.seal(..),同时也将它所有的“数据访问”属性设置为writable:false,所以他们的值不可改变。

存在性(Existence)

in和hasOwnPrototype

in操作符会检查属性是否存在于对象中,或者是否存在于[[Prototype]]链对象遍历的更高层中。
相比之下,hasOwnProperty(..) 仅仅 检查myObject是否拥有属性,但不会查询[[Prototype]]链

var myObject = {
    a: 2
};

("a" in myObject);                // true
("b" in myObject);                // false

myObject.hasOwnProperty( "a" );    // true
myObject.hasOwnProperty( "b" );    // false

枚举(Enumeration)

var myObject = { };

Object.defineProperty(
    myObject,
    "a",
    // 使`a`可枚举,如一般情况
    { enumerable: true, value: 2 }
);

Object.defineProperty(
    myObject,
    "b",
    // 使`b`不可枚举
    { enumerable: false, value: 3 }
);

myObject.b; // 3
("b" in myObject); // true
myObject.hasOwnProperty( "b" ); // true

// .......

for (var k in myObject) {
    console.log( k, myObject[k] );
}

你会注意到,myObject.b实际上 存在,而且拥有可以访问的值,但是它不出现在for..in循环中(然而令人诧异的是,它的in操作符的存在性检查通过了)。这是因为“enumerable”基本上意味着“如果对象的属性被迭代时会被包含在内”。

Object.keys()和Object.getOwnPropertyNames() 、propertyIsEnumerable

1.Object.keys()返回一个所有可枚举属性的数组,而Object.getOwnPropertyNames()返回一个 所有 属性的数组,不论能不能枚举。

2.propertyIsEnumerable()测试一个给定的属性名是否直 接存 在于对象上,并且是enumerable:true。

var myObject = { };

Object.defineProperty(
    myObject,
    "a",
    // 使`a`可枚举,如一般情况
    { enumerable: true, value: 2 }
);

Object.defineProperty(
    myObject,
    "b",
    // 使`b`不可枚举
    { enumerable: false, value: 3 }
);

myObject.propertyIsEnumerable( "a" ); // true
myObject.propertyIsEnumerable( "b" ); // false

Object.keys( myObject ); // ["a"]
Object.getOwnPropertyNames( myObject ); // ["a", "b"]

in和hasOwnProperty(..)区别于它们是否查询[[Prototype]]链,而Object.keys(..)和Object.getOwnPropertyNames(..)都 只 考察直接给定的对象。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 概述 JavaScript提供了一个内部数据结构,用来描述一个对象的属性的行为,控制它的行为。这被称为“属性描述对...
    zjh111阅读 737评论 0 0
  • 官方中文版原文链接 感谢社区中各位的大力支持,译者再次奉上一点点福利:阿里云产品券,享受所有官网优惠,并抽取幸运大...
    HetfieldJoe阅读 2,622评论 9 22
  • 特别说明,为便于查阅,文章转自https://github.com/getify/You-Dont-Know-JS...
    杀破狼real阅读 679评论 0 1
  • 尽管javascript里有大量内建引用对象,很可能你还说会频繁创建自己的对象。当你在这么做的时候,记得javas...
    WanLum阅读 541评论 1 3
  • 如果怒火可以自燃我已烧成灰烬 如果悲伤可以化水我已化成河流
    深北羽翼阅读 173评论 13 5