js–对象内部属性与 Object.defineProperty()
- 2021 年 12 月 19 日
- 筆記
- javascript
前言
JavaScript 中允许使用一些内部特性来描述属性的特征,本文来总结一下对象内部属性与 Object.defineProperty() 的相关知识。
正文
1、属性类型
js中使用某些内部属性来描述属性的特征,比如描述属性是否可以枚举,是否可以修改等特征,我们无法访直接问属性的这些特征,但是可以通过[[]]的方式来将某个特性标识为内部属性。这些内部属性分为数据属性和访问器属性。
(1)数据属性
数据属性包含一个保存数据值的位置。值会从这个位置读取,也会写入到这个位置。数据属性有 4个特性描述它们的行为。
a、[[Configurable]]表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把数据属性修改为访问器属性,默认 true。
b、[[Enumerable]]表示能否通过 for-in 循环遍历出属性 默认 true。
c、[[Writable]]表示能否修改属性的值,默认 true,设置为 false 指改属性只读。
d、[[Value]]保存这个属性的数据值,读写属性的值都是在这个位置,默认值为 undefined。
要修改对象默认数据属性,必须使用es5的 Object.defineProperty(),该方法包含三个参数,给其添加属性的对象、属性的名称和一个描述符对象。如下:
var person = {}; Object.defineProperty(person, "age", { enumerable: true, configurable: false, value: 18 }); console.log(person.age);// 18 delete person.age console.log(person.age);// 18 Object.defineProperty(person, "height", { enumerable: false, value: 50 }); console.log(person);//{age:18,height:50} for (const key in person) { console.log(key, person[key]);// age 18 } Object.defineProperty(person, "name", { writable: false, value: "Nicholas" }); console.log(person.name); // "Nicholas" person.name = "Greg"; console.log(person.name); // "Nicholas"
注意:在调用 Object.defineProperty() 时, configurable 、 enumerable 和 writable 的值如果不指定,则都默认为 false 。
(2)访问器属性
访问器属性 ==访问器属性不包含数据值,他们包含setter和getter函数,这两个函数并不是必须的
a、[[Configurable]]表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把数据属性修改为访问器属性,默认 true。
b、[[Enumerable]]表示能否通过for-in循环遍历出属性 默认 true。
c、[[Set]]写入属性的函数,默认 undefined。
d、[[Get]]读取属性的函数,默认 undefined。
同样,访问器属性是不能直接定义的,必须使用 Object.defineProperty() 。如下:
var person = { name: "Nicholas", isAdult: true }; Object.defineProperty(person, 'age', { get: function () { return this.age }, set: function (newValue) { this.isAdult = newValue >= 18 ? true : false } }); console.log(person.isAdult); person.age = 17 console.log(person.isAdult);
注意:设置了访问器属性之后不能再设置数据属性,比如设置了 set/get 就不能再设置 writable。
2、补充:内部属性的操作
(1)一次性定义多个属性
var person = {} Object.defineProperties(person, { 'name': { value: "Nicholas" }, 'isAdult': { writable: true, configurable: true, value: true }, 'age': { configurable: true, get() { return this.age }, set(newValue) { this.isAdult = newValue >= 18 ? true : false } } }) console.log(person.isAdult);// true person.age = 17// 首先到age的set方法,然后访问isAdult的writable属性并修改value值 console.log(person.isAdult);// false
(2)读取属性的特性 Object.getOwnPropertyDescriptor()获取传入对象给定属性的描述符。Object.getOwnPropertyDescriptors()获取给定对象的全部属性描述符。
var person = { name: "Nicholas", isAdult: true }; Object.defineProperty(person, 'age', { get: function () { return this.age }, set: function (newValue) { this.isAdult = newValue >= 18 ? true : false } }); var descriptor = Object.getOwnPropertyDescriptor(person, 'age') console.log(descriptor); //configurable: false // enumerable: false // get: ƒ () // set: ƒ (newValue) console.log(Object.getOwnPropertyDescriptors(person)); // {name:{...},isAdult:{...},age:{...}}
3、对象内部特性和 Object.defineProperty() 应用
(1)手写实现 const
function myConst(key, value) { window.key = value // 把要定义的key挂载到window下,并赋值value Object.defineProperty(window, key, { enumerable: false, configurable: false, get: function () { return value }, set: function (data) { if (data !== value) { // 当要对当前属性进行赋值时,则抛出错误! throw new TypeError('Assignment to constant variable.') } else { return value } } }) } myConst('a', 2) console.log(a); a = 3//报错 :Assignment to constant variable.
(2)手动实现每次访问一个属性时,值加一,使得a==1&&a==2&a==3成为可能
window.b = 0 Object.defineProperty(window, "a", { get() { this.b++ return this.b }, set(value) { this.b = value } }) if (a == 1 && a == 2 & a == 3) { console.log("111"); }//111
写在最后
以上就是本文的全部内容,希望给读者带来些许的帮助和进步,方便的话点个关注,小白的成长之路会持续更新一些工作中常见的问题和技术点。