对象属性描述符

254 阅读3分钟

一、前言

  • "Javascript 中万物都是对象",这是错误的(我是这么理解的)。对象是7个基础类型(string, number,boolean, null, undefined,object, symbol).

    对象有包含function在内的子类型,不同子类型具有不同的行为。通过Object.prototype.toString.call() 可以看属于对象中的那个子类型;[object Array]

    表示这是对象子类型数组

  • 对象就是键/值得集合,可以通过 . 或者__[ ]__ 语法来获取对象的属性

  • 访问对象属性是会执行默认__[[Get]]操作, 设置属性是会默认执行[[Put]]__

  • __[[Get]]__获取这个对象的属性是,会检查这个对象是否包含这个属性,如果没有就会通过__原型链__查找。

  • 属性的特性 可以通过属性描述符来控制。

二、属性控制符

从ES5 开始,所有的属性都有了属性描述符

let obj = {
	a:2
}
console.log(Object.getOwnPropertyDescriptor(obj,'a')) 
// value: 2, writable: true, enumerable: true, configurable: true }

1、属性描述符 包含:writable, enumerable, configurable 三个特性

let obj = {}
Object.defineProperty(obj,"a",{
	value:12,
	writable: false,
	enumerable:false,
	configurable: false
})
console.log(obj.a)
console.log(Object.getOwnPropertyDescriptor(obj,'a'))
// 12
// { value: 12, writable: false, enumerable: false, configurable: false }

2、在创建一个对象的属性时,属性描述符会使用默认值。同时也可以使用Object.defineProperty 来添加属性或者修改属性

  • 1、writable: 决定是否可以修改属性的值

    "use strict"
    let obj = {}
    Object.defineProperty(obj,"a",{
    	value:12,
    	writable: false,
    	enumerable:true,
    	configurable: true
    })
    console.log(obj.a)
    obj.a = 13
    console.log(obj.a)
    // 12
    // obj.a = 13   TypeError: Cannot assign to read only property 'a' of object '#<Object>'
    // 非严格模式下  第二个 obj.a = 12 数据不可改变
    

    你可以把writable: false 看做属性不可改变,相当于你定义了一个空操作的setter

  • 2、configurable: 只要设置为false,defineProperty() 就不可修改obj 中的属性,把configurable 修改成false 是单向操作,无法撤销

    • 但是可以将writable的状态由true改为false,但是不能由false改为true
    • 不能操作delete 方法,删除对象属性
    let obj = {}
    Object.defineProperty(obj,"a",{
    	value:12,
    	writable: true,
    	enumerable:true,
    	configurable: false
    })
    console.log(obj.a)
    obj.a = 13
    console.log(obj.a)
    delete obj.a  // TypeError: Cannot delete property 'a' of #<Object>
    
    Object.defineProperty(obj,"a",{
    	value:12,
    	writable: true,
    	enumerable:true,
    	configurable: true
    })
    
    console.log(Object.getOwnPropertyDescriptor(obj,'a'))
    
    // 12 
    // 13
    // TypeError: Cannot redefine property: a
    
    • 3、enumable:如果设为false,这个属性就不会在枚举中出现,但是可以正常访问他。

      • 当对象的enumable:false 用for-in 遍历不出这个属性
      let obj = {}
      Object.defineProperty(obj,"a",{
      	value:12,
      	writable: true,
      	enumerable:true,
      	configurable: true
      })
      Object.defineProperty(obj,"b",{
      	value:13,
      	writable: true,
      	enumerable:false,
      	configurable: true
      })
      console.log(obj) // { a: 12, b: 13 }
      for (let c in obj) {
      	console.log(c)
      }
      // a
      

总结:

  • 1、通过设置writable和configurable 值 来创建一个真正的常量属性,不可修改,不可重新定义,不可删除

  • 2、若禁止向一个对象中添加新属性,可以使用Object.preventExtensions()

  • 3、Object.seal() 会创建“密封对象”,实际上是对对象上调用Object.preventExtensions(),并把对象上的所有属性都标记为configurable:false

  • 4、Object.freeze() 会创建一个冻结对象,实际上是调用Object.seal() ,并把设置对象writable:false,这样就无法修改他们的值。是最高级别的不可变性

参考《你不知道的JavaScript 上卷》