属性描述符

您与对象属性的大部分互动可能都是 包括创建对象字面量以及设置和访问 属性值。不过,您可以在内部配置 一个对象,用于精细控制对这些属性的访问方式; 修改和定义每个对象属性都有一组不可见的属性 包含与该属性关联的元数据,称为“属性” 描述符”。

任何属性都有两种与属性相关联的描述符: 数据描述符和访问器描述符。数据描述符包括 包含属性值的键值对,无论该 可写入、可配置或可枚举。访问器描述符包含 在设置、更改或访问属性时执行的函数。

属性 描述符类型
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]]