您与对象属性的大部分互动可能都是 包括创建对象字面量以及设置和访问 属性值。不过,您可以在内部配置 一个对象,用于精细控制对这些属性的访问方式; 修改和定义每个对象属性都有一组不可见的属性 包含与该属性关联的元数据,称为“属性” 描述符”。
任何属性都有两种与属性相关联的描述符: 数据描述符和访问器描述符。数据描述符包括 包含属性值的键值对,无论该 可写入、可配置或可枚举。访问器描述符包含 在设置、更改或访问属性时执行的函数。
属性 | 描述符类型 | Object.defineProperty() 中的默认值 |
说明 |
---|---|---|---|
[[Value]] |
数据 | undefined |
包含属性的值。 |
[[Writable]] |
数据 | false |
确定您是否可以更改属性值。 |
[[Get]] |
访问者 | undefined |
属性的 getter 函数,该函数会在获取 属性。 |
[[Set]] |
访问者 | undefined |
属性的 setter 函数,该函数会在 属性。 |
[[Configurable]] |
二者都有 | false |
如果这是 false ,则无法删除该资源,并且其
无法更改。如果这是 false 且
[[Writable]] 为 true ,则该属性的值可以
也仍会更改 |
[[Enumerable]] |
二者都有 | false |
如果此值为 true ,您可以使用
for...in 循环或 Object.keys() 静态变量
方法。 |
这两个属性都使用与 [[Prototype]]
相同的简写形式,表示
不能直接访问这些属性。而应使用
Object.defineProperty()
静态方法,用于定义或修改
对象。Object.defineProperty()
接受三个参数:要对其执行操作的对象、
要创建或修改的属性键,以及一个包含
与要创建或修改的媒体资源相关联的描述符。
默认情况下,使用 Object.defineProperty()
创建的媒体资源
不可写入、可枚举或配置。不过,您创建的任何媒体资源
作为对象字面量的一部分,或者使用点或括号表示法,
可写入、可枚举和可配置。
const myObj = {};
Object.defineProperty(myObj, 'myProperty', {
value: true,
writable: false
});
myObj.myProperty;
> true
myObj.myProperty = false;
myObj.myProperty;
> true
例如,当 [[Writable]]
的值为 false
时,尝试设置新值
会在严格模式之外静默失败,并抛出
严格模式下会发生以下错误:
{
const myObj = {};
Object.defineProperty(myObj, 'myProperty', {
value: true,
writable: false
});
myObj.myProperty = false;
myObj.myProperty;
}
> true
(function () {
"use strict";
const myObj = {};
Object.defineProperty(myObj, 'myProperty', {
value: true,
writable: false
});
myObj.myProperty = false;
myObj.myProperty;
}());\
> Uncaught TypeError: "myProperty" is read-only
有效利用描述词是一个相当高级的概念,
理解对象的内部结构至关重要
以更常见的方式处理对象时涉及的语法。例如:
这些概念在使用 Object.create()
静态方法时需要用到,
这使你可以精细控制附加到新模型
对象。
Object.create()
使用现有对象作为其
原型设计这可让新对象从其他对象继承属性和方法
用户定义的对象,其方法与从该对象继承属性的方式相同
JavaScript 内置的 Object
原型。当您使用以下代码调用 Object.create()
时,
对象作为参数时,该函数会创建一个空对象,并将传递的对象
原型设计。
const myCustomPrototype = {
'myInheritedProp': 10
};
const newObject = Object.create( myCustomPrototype );
newObject;
> Object { }
<prototype>: Object { myInheritedProp: 10 }
myInheritedProp: 10
<prototype>: Object { … }
Object.create
可以采用第二个参数,为
使用类似于 Object.defineProperty()
的语法新建对象的 -
也就是说,一个对象将键映射到一组描述符属性:
const myCustomPrototype = {
'myInheritedProp': 10
};
const myObj = Object.create( myCustomPrototype, {
myProperty: {
value: "The new property value.",
writable: true,
configurable: true
}
});
myObj;
> Object { … }
myProperty: "The new property value."
<prototype>: Object { myInheritedProp: 10 }
在此示例中,新对象 (myObj
) 使用一个对象字面量
(myCustomPrototype
) 作为其原型,而其本身包含继承的
Object.prototype
,从而生成一系列继承的原型,称为
原型链。每个对象都有一个原型(无论是被分配还是继承),
该容器拥有自己的已分配或继承的原型。此链的结束时间为
null
原型设计,它本身没有原型。
const myPrototype = {
'protoProp': 10
};
const newObject = Object.setPrototypeOf( { 'objProp' : true }, myPrototype );
newObject;
> Object { objProp: true }
objProp: true
<prototype>: Object { protoProp: 10 }
protoProp: 10
<prototype>: Object { … }
值的原型中包含的属性在“顶级”可用 而无需直接访问原型属性:
const objectLiteral = {
"value" : true
};
objectLiteral;
> Object { value: true }
value: true
<prototype>: Object { … }
objectLiteral.toString();
"[object Object]"
此模式适用于与某个对象相关联的整个原型链 对象:在尝试访问某个属性时,解释器会查找该属性, 每个“级别”的媒体资源从上到下,一直到 找到属性或链的结束位置:
const myCustomPrototype = {
'protoProp': "Prototype property value."
};
const myObj = Object.create( myCustomPrototype, {
myProperty: {
value: "Top-level property value.",
writable: true,
configurable: true
}
});
myObj.protoProp;
> "Prototype property value."
检查您的理解情况
哪些描述符属于访问器?
[[Get]]
[[Set]]
[[Writable]]