定义一个变量

属性描述符(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(..)都 只 考察直接给定的对象。

你可能感兴趣的:(定义一个变量)