JavaScript对象——属性描述符

来源:互联网 发布:剑灵男灵族捏脸数据 编辑:程序博客网 时间:2024/05/21 06:29

定义对象有两种方式:

var obj = {"a":1,"b":2}

或者

var obj = new Object();obj.a = 1;obj.b = 2;

我们一般都会用第一种方式吧?第二个还要逐个添加呢,太麻烦了。
有没有想过定义一个属性a,难道这个a就是光杆司令,只有一个值吗?
其实吧,每一个属性都有一群小兵呢,它们叫做属性描述符,就是详细描述这个属性的。看代码:

var obj = {"a":1};Object.getOwnPropertyDescriptor(obj,"a");//{//  value: 1//  writable: true//  enumerable: true//  configurable: true//}

哇!一个属性都这么多东西呢。不着急,下面我们一个一个来研究它们都是干嘛的。


writable

writable决定是否可以修改属性的值。

var obj = {};Object.defineProperty(obj,"a",{    value: 1,    writable: false,    //注意!不可写    configurable: true,    enumerable: true})obj.a;  //1obj.a = 2;obj.a;  //1

看到没有,我们通过Object.defineProperty()方法定义了属性a以及它的属性描述符。当属性描述符writablefalse的时候,对该属性重新赋值是没有效果的。
上面代码是在非严格模式下的,如果在严格模式下面呢:

'use strict';var obj = {};Object.defineProperty(obj,"a",{    value: 1,    writable: false,    //注意!不可写    configurable: true,    enumerable: true})obj.a = 2;  //Uncaught TypeError: Cannot assign to read only property 'a' of object

语法错误,不可以修改只读的属性。


configurable

只要属性是可配置的,就可以使用defineProperty()方法修改属性描述符。

var obj = {a:2};obj.a = 3;obj.a;  //3Object.defineProperty(obj,"a",{    value: 4,    writable: true,    configurable: false,    //不可配置    enumerable: true});obj.a;    //4obj.a = 5;obj.a;    //5(赋值是可以的,有writable控制)Object.defineProperty(obj,"a",{    value: 6,    writable: true,    configurable: true,    enumerable: true});    //TypeError: Cannot redefine property: a

注意

  • 即使属性是configurable: false,也可以把writable的状态由true改为false,但是无法由false改为true。
  • 除了无法修改,configurable: false还会禁止删除这个属性:
var obj = {a:2};obj.a;    //2delete obj.a;obj.a;    //undefinedObject.defineProperty(obj,"a",{    value: 2,    writable:true,    configurable: false,    enumerable: true});obj.a;    //2delete obj.a;obj.a;    //2,没有删除该属性

enumerable

控制属性是否会出现在对象的属性枚举中。

var obj = {};Object.defineProperty(obj,"a",{    value: 2,    enumerable: true});Object.defineProperty(obj,"b",{    value: 3,    enumerable: false});obj.b;    //3,虽然不可枚举,但是可以访问("b" in obj);    //trueobj.hasOwnProperty("b");    //truefor(var k in obj) {    console.log(k, obj[k]);    //"a" 2}

注意:for..in不要用于数组。因为in可以检查是否有某个属性值,如果一个数组含有其他属性(当然给数组添加属性不常见),遍历数组的话,和你想象的不一样:

var arr = [1,2,3];arr.a = 1;for(var k in arr)        console.log(k, arr[k]);    //0 1//1 2//2 3//a 1

我们也可以通过另一种方式来区分属性是否可以枚举:

var obj = {};Object.defineProperty(obj,"a",{    value: 2,    enumerable: true});Object.defineProperty(obj,"b",{    value: 2,    enumerable: false});obj.propertyIsEnumerable("a");    //trueobj.propertyIsEnumerable("b");    //falseObject.keys(obj);    //["a"]Object.getOwnPropertyNames(obj);    //["a", "b"]
  • propertyIsEnumerable()会检查给定的属性名是否直接存在于对象中(而不是在原型链上),并满足enumerable: true。
  • Object.keys()和Object.getOwnPropertyNames()都只会查找对象直接包含的属性。
  • Object.keys()会返回一个数组,包含所有可枚举属性。
  • Object.getOwnPropertyNames()会返回一个数组,包含所有属性,无论它们是否可枚举。
  • in和hasOwnProperty()的区别在于是否查找原型链
Object.prototype.a = 1;var obj = {b: 2};for(var k in obj) {    console.log(k);    //b, a }

可以看到,in在查找对象属性时遍历原型链上的所有属性。

原创粉丝点击