ECMA-262 定义对象

对象是一组属性的无序集合。

  • 无序 没有特定顺序的值
  • 对象每个属性和方法

    • 一组 名/值 对
    • 值可以是 数据 或 函数

      属性类型

      内部用来描述属性的特征。又称为属性描述符。

      数据属性

  • [[Configurable]]

可配置

  • 表示属性
    1. 是否通过 delete 删除并重新定义,
    2. 是否可以修改特征
    3. 是否可以改为访问器属性
  • 默认 true (如果被设置为 false,就不能再变回可配置)
    • [[Enumerable]]
      可枚举
  • 表示属性是否通过 for-in 循环返回
  • 默认 true
    • [[Writable]]
      可写
  • 表示属性的值是否可以被修改
  • 默认 true
    • [[Value]]
  • 表示属性实际的值
  • 默认 undefined

    使用显式定义对象,除 [[Value]] 外,其它数据属性都会以其默认值 true。而 [[Value]] 设置为指定的值。

调用 Object.defineProperty() / Object.defineProperties() 不指定 configurable、enumerable、writable 值,默认为 false。

访问器属性

  • [[Configurable]]

可配置

  • 表示属性
    1. 是否通过 delete 删除并重新定义,
    2. 是否可以修改特征
    3. 是否可以改为访问器属性
  • 默认 true (如果被设置为 false,就不能再变回可配置)
    • [[Enumerable]]
      可枚举
  • 表示属性是否通过 for-in 循环返回
  • 默认 true
    • [[Get]]
      getter
  • 获取函数,读取属性时调用
  • 默认 undefined
    • [[Set]]
      setter
  • 设置函数,写入属性时调用
  • 默认 undefined

    getter 取值函数 和 setter 存值函数

    设置 getter 会取代 value
    设置 setter 会取代 writable
    1. var obj = {
    2. a: 1,
    3. get c(){
    4. console.log('getter:');
    5. return this.a;
    6. },
    7. set c(val){
    8. console.log('setter:', val);
    9. this.a = val * 2;
    10. }
    11. }
    getter 与 setter 最好成对出现,如果单独定义
  1. 只定义 getter 函数,静默失败,严格模式会报错 ```javascript var obj = { get a(){ return 2; } }

console.log(obj.a); // 2 obj.a = 10; // 这里会执行,但会静默失败。在严格模式下会报错 console.log(obj.a); // 2

  1. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1753568/1622377742028-5f74d46f-fa4a-4bfb-b55e-696845f0603d.png#clientId=u0166b12d-f5b9-4&from=paste&height=50&id=u685f3155&margin=%5Bobject%20Object%5D&name=image.png&originHeight=50&originWidth=519&originalType=binary&ratio=1&size=39470&status=done&style=none&taskId=u782c37f6-e62b-4c03-83f0-aab82145976&width=519)
  2. 2. 只定义 setter 函数,获取属性值为 undefined
  3. 2. 所以 gettersetter 一定要成对出现
  4. ```javascript
  5. var obj = {
  6. set a(val){
  7. console.log(val); // 10
  8. return 2;
  9. }
  10. }
  11. console.log(obj.a); // undefined
  12. obj.a = 10;
  13. console.log(obj.a); // undefined

访问器属性可以通过 Object.defineProperty() / Object.defineProperies()
或者
定义对象属性前使用 get / set 修饰符

var book = { year_:2017, edition: 1 }; 
Object.defineProperty(book, 'year', { 
  get: function() { 
    return this.year_; 
  }, 
  set: function(newValue){ 
    if (newValue > 2017) { 
      this.year_ = newValue; 
      this.edition += newValue - 2017; 
    } 
  } 
}); 

// 或者 Object.defineProperties() 多个属性一起定义
var book = {};
Object.defineProperties(book, {
    year_: {
      value: 2017,
    writable: true // Object.defineProperty() / Object.defineProperties()
                             // 不指定 configurable、enumerable、writable 值,默认为 false
  },
  edition: {
      value: 1,
    writable: true // 原理同上,writable 为 false,下面的 year setter 就没有任何效果了
  },
  year: {
    get: function() { 
      return this.year_; 
    }, 
    set: function(newValue){ 
      if (newValue > 2017) { 
        this.year_ = newValue; 
        this.edition += newValue - 2017; 
      } 
    } 
  }
});

// 或者 在显式定义对象中使用 get / set 修饰符,更加简化
var book = { 
  year_:2017, edition: 1, 
  get year(){ 
    return this.year_; 
  },
  set year(newValue){
    if (newValue > 2017) { 
      this.year_ = newValue; 
      this.edition += newValue - 2017; 
    } 
  }
};

IE8 兼容性

IE8 的 Object.definedProperty() 只支持 DOM,但可以使用两个非标准的访问创建访问器属性

  • defineGetter()
  • defineSetter() ```javascript var book = {year_:2017, edition: 1};

book.defineGetter(‘year’, function(){ return this.year_; });

book.defineSetter(‘year’, function(newValue){ if (newValue > 2017) { this.year_ = newValue; this.edition += newValue - 2017; } });

> 不支持 `Object.defineProperty()` 的浏览器中没有办法修改 [[Configurable]] 或 [[Enumerable]]

<a name="QXatt"></a>
# 对象禁止配置
不允许对象增加属性
```javascript
Object.prototype.isExtensable(obj);
Object.prototype.preventExtensions(obj);

对象封印

不允许对象增加、删除属性

Object.prototype.isSealed(obj);
Object.prototype.seal(obj);

对象冻结

不允许对象增加、更改、删除属性

Object.prototype.isFrozen(obj);
Object.prototype.freeze(obj);