JS的数据属性和访问器属性
![](https://cdn.nlark.com/yuque/0/2020/png/305942/1597237859226-b5c07396-ab8f-4992-a5ba-893706189057.png)
ECMA-262第5版在定义只有内部才用的特性(attribute)时,描述了属性(property)的各种特征。ECMA-262定义这些特性是为了实现javascript引擎用的,因此在javascript中不能直接访问它们。为了表示特性时内部值,该规范把它们放在了两对方括号中,例如[[Enumerable]]。
数据属性
数据属性包含一个数据值的位置,在这个位置可以读取和写入值。数据属性有4个描述其行为的特性
类别
Value
包含这个属性的数据值。读取属性值的时候,从这个位置读取,写入值得时候,把新值保存在这个位置。这个特性得默认值为undefined
Configurable
表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。直接在对象上定义的属性,它们的这个特性默认值为true
Enumerable
表示能否通过for-in循环返回属性,直接在对象上定义的属性,它们的这个特性默认值为true
Writable
表示能否修改属性的值,直接在对象上定义的属性,它们的这个特性默认值为true
修改
要修改默认的特性,必须使用ES5的Object.defineProperty()方法
// 使用方式 Object.defineProperty( obj, prop, descriptor) obj:需要定义属性的对象。 prop:需定义或修改的属性的名字。 descriptor:一个包含设置特性的对象 // 例子 var person = {name: "percy"}; Object.defineProperty(person,"name",{ writable: false });
读取
通过,Object.getOwnPropertyDescriptor()方法获取指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)
var girl = {name: "zyj"}; console.log(Object.getOwnPropertyDescriptor(girl,"name")); // Object {value: "zyj", writable: true, enumerable: true, configurable: true}
注意⚠️
- 直接在对象上定义的属性,它们的[[Configurable]]、[[Enumerable]]、[[Writable]]特性都被设置为true,[[Value]]特性被设置为了指定的值.
访问器属性
访问器属性不包含数据值,它们包含一对getter和setter函数(这两个函数都不是必须的)。在读取访问器属性时会调用getter函数,这个函数会负责返回有效的值,在写入访问器属性时,会调用setter函数并传入新值。这个函数负责决定如何处理数据。访问器属性有如下4个特性
类别
Configurable
表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性。直接在对象上定义的属性,这个特性的默认值为true
Enumerable
表示能否通过for-in循环返回属性。直接在对象上定义的属性,这个特性的默认值为true
Get
在读取属性时调用的函数。默认值为undefined
Set
在写入属性时调用的函数。默认值为undefined
定义
访问器属性不能直接定义,必须使用Object.defineProperty()定义单个或者Object.defineProperties()来定义
定义单个。注意⚠️:用Object.defineProperty()定义的访问器属性,其configurable和enumerable默认为false。
var book = { year : 2004, edition : 1 }; Object.defineProperty(book,"year",{ get : function () { alert(this.year); }, set : function (newValue) { if (newValue > 2004) { this.year = newValue; this.edition += newValue - 2004; } } }); book.year; // 弹出窗口,显示 2004 book.year = 2005; console.log(book.edition); // 2
定义多个
var obj = {}; Object.defineProperties(obj, { "property1": { value: true, writable: true }, "property2": { value: "Hello", writable: false } });
读取
通过,Object.getOwnPropertyDescriptor()方法获取指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)
var descriptor = Object.getOwnPropertyDescriptor(girl,"age"); console.log(descriptor.value); // 22 console.log(descriptor.configurable); // false console.log(descriptor.writable); // true console.log(descriptor.get); // undefined console.log(descriptor.set); // undefined
注意⚠️
用Object.defineProperty()定义的访问器属性,其configurable和enumerable默认为false。
数据属性和访问器属性互相转化
数据属性 -> 访问器属性
属性的特性只能是访问器描述符和数据描述符中的一种,给已有的数据属性加get或set转换为访问器属性时,其属性的value、writable就会被废弃。
// 设置get和set其中任意一个即可转换为访问器属性 Object.defineProperty(person, "year", { get: function() { return this._year; }, set: function(value) { this._year= value; } }) var descriptor = Object.getOwnPropertyDescriptor(person, 'year'); console.log(descriptor); // {get: ƒ, set: ƒ, enumerable: true, configurable: true}
访问器属性 -> 数据属性
将访问器属性转换为数据属性,只需要给现有访问器属性设置value或writable这两个属性描述符中的任意一个即可,其原有的get和set就会被废弃,从而转换为数据属性。
注意⚠️:可以在访问器属性和数据属性间相互转化的属性其configurable特性值必须为true。configurable为false,则不可以将其转换为数据属性。
Object.defineProperty(person, "job", { configurable: true, enumerable: true, get: function() { return this._job; }, set: function(value) { this._job = value; } }); // 设置value和writable其中任意一个即可转换为数据属性 Object.defineProperty(person, "job", { value: 'worker', writable: true }); var descriptor = Object.getOwnPropertyDescriptor(person, 'job'); console.log(descriptor); // {value: "worker", writable: true, enumerable: true, configurable: true}
扩展:如何定义对象
定义对象一共有如下四种方式
- 使用语法结构创建的对象
- 使用构造器创建的对象
- 使用 Object.create 创建的对象
- 使用 class 关键字创建的对象
下面我们分别来给个例子🌰
使用语法结构创建对象
var o = {a: 1};
使用构造器创建对象
function Graph() { this.vertices = []; this.edges = []; } var g = new Graph();
使用 Object.create 创建对象
var a = {a: 1}; var b = Object.create(a);
使用 class 关键字创建的对象
class Polygon { constructor(height, width) { this.height = height; this.width = width; } } let polygon = new Polygon();
参考
MDN文档
https://blog.csdn.net/weixin_43936704/article/details/103930693https://www.cnblogs.com/he-ming-min/p/11011402.htmlhttps://www.cnblogs.com/absolute-child/p/7188417.htmlhttps://www.cnblogs.com/shiningly/p/9482283.html?utm_source=debugrun&utm_medium=referral