属性描述符
假设有一个对象
obj
var obj = {a:1
}
观察这个对象,我们如何来描述属性
a
:
- 值为1
- 可以重写
- 可以遍历
- 我们可以通过
Object.getOwnPropertyDescriptor
得到它的属性描述符
var desc = Object.getOwnPropertyDescriptor(obj, 'a');
console.log(desc);
我们会得到一个对象
观察这个对象中的内容
configurable : true
:表示描述符本身能否修改enumerable : true
:是否可遍历value : 1
:值writable : true
:是否可重写
- 设置属性描述符
Object.defineProperty(obj, 'a', {value:10,writable:false //表示不可重写
});
console.log(obj.a); // 10
- 注:如果修改了
configurable
的值为false
,后续再次修改属性描述符会报错。
Object.defineProperty(obj, 'a', {configurable:false
});
Object.defineProperty(obj, 'a', {value:20,
});
console.log(obj.a);
- 但是,如果属性设置了不可重写,后续进行修改,虽然不会报错,但是不会修改成功
Object.defineProperty(obj, 'a', {value:10,writable:false //表示不可重写
});
console.log(obj.a); // 10
obj.a = 20;
console.log(obj.a); // 10
因此,如果属性不能重写,后续修改最好能进行报错,告诉用户哪句话出现了问题。
- 为了解决上面的问题,
Object.defineProperty
中有两个函数- 读取器 getter
- 设置器 setter
当读取属性a的值的时候会运行get函数,设置属性a的值的时候会 运行set函数
Object.defineProperty(obj, 'a', {get:function(){console.log("get函数");},set:function(val){console.log("set函数");}
});
obj.a = 20; // set函数
console.log(obj.a); // get函数
注:这里需要注意一个问题—无限递归问题
- 如果在get中读取属性,或者在set中设置属性的值,则会出现无限递归问题
Object.defineProperty(obj, 'a', {get:function(){return obj.a;},set:function(val){obj.a = val;}
});
obj.a = 20;
console.log(obj.a);
- 使用样例
var internalValue = obj.a;
Object.defineProperty(obj, 'a', {get:function(){console.log("get函数");return internalValue;},set:function(val){console.log("set函数");internalValue = val;return internalValue;}
});
obj.a = 20; // set函数
console.log(obj.a); // get函数 20
- 因此,假设该属性不能重写,可以在set函数中抛出一个报错信息,提示用户
Object.defineProperty(obj, 'a', {get:function(){console.log('get函数');},set:function(val){throw new Error(`报错信息:该属性不能赋值,你正在给这个属性赋值为${val}`);}
})
console.log(obj.a);
obj.a = 20;
当然,这里面也会出现问题需要考虑,具体出现的问题具体分析。