属性的descriptor可描述对象

107 阅读2分钟

1、概述:

JavaScript 提供了一个内部[数据结构],用来描述对象的属性,控制它的行为,比如该属性是否可写、可遍历等等。这个内部数据结构称为“属性描述对象”(attributes object)。每个属性都有自己对应的属性描述对象,保存该属性的一些元信息

2、属性的元信息

{
    configurable:true,
    writable:true,
    enumerable:true,
    value:'',
    get(){

    },
    set(){

    }
}

2.1 value属性

  • configurable或writable其中一个为true时,才能修改成功
let proto = {
    foo:'foo',
    foo1:'foo1',
}
Object.defineProperty(proto,'foo',{
    configurable:false,
    writable:false,
    enumerable:false,

})
proto.foo = 'zs';  //修改失败
console.log(proto.foo);
  • 可直接对象点属性获取,或者
Object.getOwnPropertyDescriptor(proto,'foo').value

2.2 configurable属性

  • 布尔值,决定了是否可以修改属性描述对象,当configurable:false,value、writable、enumerable、configurable都不能被修改。
let proto = {
    foo:'foo',
    foo1:'foo1',
}
Object.defineProperty(proto,'foo',{
    configurable:false,
    writable:false,
    enumerable:false,
})
Object.defineProperty(proto,'foo',{
    configurable:true,
})
// TypeError: Cannot redefine property: foo
Object.defineProperty(proto,'foo',{
    writable:true,
})
// TypeError: Cannot redefine property: foo
Object.defineProperty(proto,'foo',{
    enumerable:true,
})
// TypeError: Cannot redefine property: foo
Object.defineProperty(proto,'foo',{
    value:1,
})
// TypeError: Cannot redefine property: foo

2.3 writable属性

  • 布尔值,决定了目标属性的值,即value是否可被修改
let proto = {
    foo:'foo',
    foo1:'foo1',
}
Object.defineProperty(proto,'foo',{
    // configurable:false,
    writable:false,
    // enumerable:false,
})
proto.foo = 'zs'; //修改失败
console.log(proto.foo); // foo
  • 如果原型对象的某个属性的writablefalse,那么子对象将无法自定义这个属性
let proto = {
    foo:'foo',
    foo1:'foo1',
}
Object.defineProperty(proto,'foo',{
    // configurable:false,
    writable:false,
    // enumerable:false,
})
let obj = Object.create(proto);
obj.foo = 'zs';  //修改失败
console.log(obj.foo);  //foo
  • 重定义子对象属性的可描述对象,解决原型对象的某个属性的writablefalse,子对象将无法自定义这个属性
let proto = {
    foo:'foo',
    foo1:'foo1',
}
Object.defineProperty(proto,'foo',{
    // configurable:false,
    writable:false,
    // enumerable:false,
})
let obj = Object.create(proto);
Object.defineProperty(obj,'foo',{
    writable:true
})
obj.foo = 'zs';  //修改成功
console.log(obj.foo);  //zs

2.4 enumerable属性

  • (可遍历性)返回一个布尔值,表示目标属性是否可遍历
  • in会遍历toString这一类实例对象继承的原生属性
var obj = {};
console.log('toString' in obj); // true
  • 只有可遍历的属性,才会被for...in循环遍历,规定toString这一类实例对象继承的原生属性,都是不可遍历的,这样就保证了for...in循环的可用性
  • enumerable:false时,以下三种操作不能使用该属性
    • for...in
    • Object.keys()
    • JSON.stringify
  • for...in循环会遍历出继承的属性,而Object.keys()不会,Object.getOwnPropertyNames方法可获取对象自身的所有方法,包含可遍历和不可遍历。

2.5 存取器

  • 适用于属性依赖于对象内部其他属性的场景
  • 属性还可以用存取器(accessor)定义,存值属性称为setter函数,使用属性描述对象的set属性;取值属性称为getter函数,使用属性描述对象的get属性
let proto = {
    foo:'foo',
    $foo:'foo',
}
Object.defineProperty(proto,'foo',{
    // configurable:false,
    // writable:false,
    // enumerable:false,
    get(){
        return this.$foo;
    },
    set(value){
        this.$foo = value
    }
})
console.log(proto.foo); //foo
proto.foo = 'fooNew';
console.log(proto.foo);  //fooNew
  • 另一种写法:其中get不接受参数,set接受一个参数(即属性的值)
let obj = {
    $name:'zs',
    get name(){
        return this.$name;
    },
    set name(value){
        console.log('setter');
        this.$name = value;
    }
}
console.log(obj.name); //zs
obj.name = 'li'
console.log(obj.name);  //li