1

属性描述对象

何为属性描述对象

就是用来描述对象属性的对象,其作用就是规定了属性的行为,即拥有属性和方法
一共有6个控制属性的属性;在介绍前必须先熟悉操作和访问属性描述对象的方法

Object.getOwnPropertyDescriptor()

此方法用于获取自身(继承的不行,也就是不能越级)属性的属性描述对象,两个参数,第一个参数是目标对象,
第二个参数是字符串,目标对象的属性名

```
var obj = {name : 123};
obj.getOwnPropertyDescriptor(obj, "name"); 
//{value: 123, writable: true, 
//enumerable: true, configurable: true}
```

Object.defineProperty(),Object.defineProperties()

  • Object.defineProperty()
    Object.defineProperty(object, propertyName, attributesObject)用于设置一个属性的属性描述对象,
    object:目标对象
    propertyName:目标对象属性
    attributesObject:要设置的属性描述对象

    var obj = Object.defineProperty({}, "p", {
        value : "aaa",
        writable : false,
        enumerable : true,
        configurable : false,
    })
  • Object.defineProperties()
    Object.defineProperties()可以一次性设置多个属性的属性描述对象

    var obj ={};
    Object.defineProperties(obj1, {
        a : {value : 123},
        b : {value : 456, enumerable : true},
        })
    console.log(obj);      //{b : 456, a : 123}

Object.prototype.propertyIsEnumerable()

Object.prototype.propertyIsEumerable(elem),作用为该属性是否可以枚举,填入一个字符串,(值为属性名),返回一个布尔值;这是一个实例方法

var obj = [1, 2];
obj.name = "arr";
obj.propertyIsEnumerable("name");     //true
obj.propertyIsEnumerable("length");   //false
obj.propertyIsEnumerable("0");        //true

6大元属性

能控制属性的属性称为元属性

  • value
    设置该属性的属性值,默认值为undefined

    var obj = Object.defineProperty({}, "p", {value : 123});
    obj["p"];   //123
  • writable
    表示属性值(value)外部能否直接赋值,writable是一个布尔值,默认值是true
    在用defineProperty()设置属性时,writable默认值为fasle;同理enumerable,configurable也是如此

    var obj = Object.defineProperty({}, 'p', {value : 123});
    Object.getOwnPropertyDescriptor(obj, 'p');
    //{ value: 123, writable: false, enumerable: false, configurable: false}
    
    var obj1 = {p :123};
    Object.getOwnPropertyDescriptor(obj1, 'p');
    //{ value: 123, writable: true, enumerable: true, configurable: true} 

    如值为false,外部无法直接赋值改变

    var obj = {a : 1};
    Object.defineProperty(obj, "a", {writable : false});
    obj.a = 2;
    console.log(obj.a);  //1,严格模式下这么做会报错
  • enumerable
    表示该属性是否可以枚举,即是否可以遍历默认是值为true,如值为false,则无法被for-in,JSON.stringify以及Object.keys()

    var obj = {
        a : 1,
        b : 2,
        c : 3,
    };
    Object.defineProperty(obj, "a", {enumerable: false});
    for(var i in obj) {
        console.log(i);
    }
    //b
    //c
  • configurable
    其值为布尔值,决定来是否可以修改属性描述对象,也就是当值为false时,enumerable,configurable,这两者不能再被修改,不然会报错:TypeError

    注意点

    • writable只有当false改为true时会把错,由true改为false时不会报错

      var obj = Object.defineProperty({}, "a", {
              value : 123,
              //writable : false,
              writable : true
              enumerable : true,
              configurable : false,
          });
          //Object.defineProperty(obj, "a", {writable : true}) 报错
          Object.defineProperty(obj, "a", {writable :false});  //可以修改
    • value值只有在writable和configurable至少一个为true时才能修改不然报错
    • configurable为false时则属性不能被删除

      var obj = {
          a : 1,
          b : 2,
      }; 
      Object.defineProperty(obj, "b", {configurable : false});
      delete obj.a;
      delete obj.b;
      console.log(obj);  //{b : 2}
  • get,set
    get:取值,在对象取值时会跳用getter函数,默认值undefined,例如obj.a
    set:存值,在对象赋值时会调用setter函数,默认值undefined,例如obj.a = 123;
    注意点:当设置了set或者get元属性时,若设置了writable,或者设置value 属性,会报错:Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute,

    var obj = Object.defineProperty({}, "a", {
            get : function () {
                return "getter"
            }
            set : function (value) {
                console.log(value);
            },
    
        })

    写法2:

    var obj = {
            get a() {
                return "getter";
            },
            set a(value) {
                console.log(value);
            }
        }
        obj.a = 123;

控制对象的状态

Object.preventExtensions:能删除修改旧属性,不能添加新属性
Object.seal:不能删除旧属性,但能赋值修改旧属性,不能添加新属性,相当于把configurable:false
Object.freeze:不能删除修改旧属性,不能添加新属性,相当于对象变为常量
        var obj1 = {a : 1};
        var obj2 = {a : 1};
        var obj3 = {a : 1};
        Object.preventExtensions(obj1);   //旧属性能删除,能修改属性对象value,能外部直接赋值
        //obj1.a = 2;
        //delete obj1.a;
        //Object.defineProperty(obj1, "a", {value : 3});
        //obj1.b = 2;                                      //新属性不能进行赋值
        //Object.defineProperty(obj1, "b", {value : 3});   //不能添加新的属性描述对象,会保错
        Object.seal(obj2);                //旧属性不能删除,能修改属性对象value,能外部直接赋值
        // obj2.a = 2;

        //delete obj2.a;
        // Object.defineProperty(obj2, "a", {value : 3});
        //obj2.b = 2;                                      //新属性不能进行赋值
        //Object.defineProperty(obj2, "b", {value : 3});   //不能添加的新属性描述对象,会保错
        Object.freeze(obj3);              //旧属性不能删除,不能修改属性对象value,不能外部直接赋值
        obj3.a = 2;

        //delete obj3.a;
        //Object.defineProperty(obj3, "a", {value : 3});
        //obj3.b = 2;                                      //新属性不能进行赋值
        //Object.defineProperty(obj3, "b", {value : 3});     //不能添加的新属性描述对象,会保错

注意点:

  • 冻结的是对象自身的属性,但是可以通过给原型添加属性来实现

    var obj = {a :1};
    Object.freeze(obj);
    console.log(obj.b);    //undefined
    var obj0 = Object.getPrototypeOf(obj);
    obj0.b = 2;
    console.log(obj.b);    //2
  • 当然我们可以冻结原型

    var obj = {a :1};
    Object.freeze(obj);
    console.log(obj.b);              //undefined
    var obj0 = Object.getPrototypeOf(obj);
    Object.freeze(obj0);
    obj0.b = 2;
    console.log(obj.b);              //undefined
  • 但是对于属性值为object类型的,我们冻结的是它的地址不变,但其内容还是可以变得

    var obj = {a :{b : 1}};
    Object.freeze(obj);
    console.log(obj.a);              //{b : 1}
    obj.a.b = 2;
    console.log(obj.a);              //{b : 2}
    obj.a.c = 3;
    console.log(obj.a);              //{b : 2, c : 3}

三个检测是否冻结的方法

Object.isExtensible:能否为对象添加新属性
Object.isSealed:是否使用了Object.seal()
Object.isFrozen:是否使用了Object.freeze()


Infinity
293 声望9 粉丝

学前端中,只想激情优雅的写代码