Skip to content

对象增强 ​

一、Object.defineProperty ​

属性都是直接定义在对象内部,或者直接添加到对象内部的

但是这样就不能对这个属性进行一些限制;比如属性是否可以通过 delete 删除,是否能在for in遍历的时候被遍历出来

如果想要对一个属性进行比较精准的操作控制,就可以使用属性描述符

  • 通过属性描述符可以精准的添加或者修改对象的属性
  • 属性描述符需要使用Object.defineProperty来对属性进行添加或者修改

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象

javascript
Object.defineProperty(obj, prop, descriptor)

可接受三个参数:

  • obj 是要定义属性的对象
  • prop 是要定义或修改的属性名称或 Symbol
  • descriptor 是要定义或修改的属性描述符

返回值

  • 被传递给函数的对象

属性描述符的类型有两种:

  • 数据属性描述符
  • 存取属性描述符

二、数据属性描述符 ​

数据属性描述符有四个特性:

  • [[Configuable]]: 表示属性是否可以通过 delete 删除属性,是否可以修改它的特性,或者是否可以将它修改为存取属性描述符

    • 当直接在对象上定义某个属性时,这个属性的 [[Configuable]] 为 true
    • 当通过属性描述符定义一个属性时,这个属性的 [[Configuable]] 为 false
    javascript
    var obj = {
    	name: 'mocha',
    	age: 18,
    }
    
    Object.defineProperty(obj, 'name', {
    	configurable: false, // 告诉js引擎,obj对象的name属性不可以被删除
    })
    
    delete obj.name
    console.log(obj) // { name: 'mocha', age: 18 }
    
    // 通过 Object.defineProperty 添加一个新的属性
    Object.defineProperty(obj, 'address', {})
    delete obj.address
    console.log(obj) // { name: 'mocha', age: 18 }
  • [[Enumerable]]: 表示属性是否可以通过for-in或者Object.keys()返回该属性

    • 当直接在对象上定义某个属性时,这个属性的 [[Enumerable]] 为 true
    • 当通过属性描述符定义一个属性时,这个属性的 [[Enumerable]] 为 false
    javascript
    var obj = {
    	name: 'mocha',
    	age: 18,
    }
    
    Object.defineProperty(obj, 'name', {
    	enumerable: false,
    })
    
    const keys = Object.keys(obj)
    console.log(keys) // age
  • [[Writable]]: 表示是否可以修改属性的值

    • 当直接在对象上定义某个属性时,这个属性的**[[Writable]]** 为 true
    • 当直接通过属性描述符定义属性时,这个属性的**[[Writable]]** 为false
    javascript
    var obj = {
    	name: 'mocha',
    	age: 18,
    }
    
    Object.defineProperty(obj, 'name', {
    	writable: false,
    })
    
    obj.name = 'latte'
    console.log(obj.name) // mocha
  • [[value]]: 属性的 value 值,读取属性时会返回该值,修改属性时,会对其进行修改

    • 默认情况下这个值是 undefined
    javascript
    var obj = {}
    
    Object.defineProperty(obj, 'name', {
    	configurable: false,
    	enumerable: false,
    	writable: false,
    	value: 'mocha',
    })
    
    console.log(obj.name) // mocha

三、存取属性描述符 ​

存取属性描述符有四个特性:

  • [[Configuable]]: 表示属性是否可以通过 delete 删除属性,是否可以修改它的特性,或者是否可以将它修改为存取属性
    • 和数据属性描述符一致
    • 当直接在对象上定义某个属性时,这个属性的 [[Configuable]] 为 true
    • 当通过属性描述符定义一个属性时,这个属性的 [[Configuable]] 为 false
  • [[Enumerable]]: 表示属性是否可以通过for-in或者Object.keys()返回该属性
    • 和数据属性描述符一致
    • 当直接在对象上定义某个属性时,这个属性的 [[Enumerable]] 为 true
    • 当通过属性描述符定义一个属性时,这个属性的 [[Enumerable]] 为 false
  • [[get]]: 获取属性时会执行的函数,默认为undefined
  • [[set]]: 设置属性时会执行的函数,默认为undefined
javascript
var obj = {}

var _name = ''

Object.defineProperty(obj, 'name', {
	configurable: true,
	enumerable: false,
	set: function (value) {
		console.log('set方法被调用了', value)
		_name = value
	},
	get: function () {
		console.log('get方法被调用了')
		return _name
	},
})

obj.name = 'mocha' // 赋值后set函数被执行:set方法被调用了 mocha
obj.name = 'latte' // 赋值后set函数被执行:set方法被调用了 latte

console.log(obj.name) // get方法被调用了  latte

四、Object.defineProperties ​

Object.defineProperties() 方法直接在对象上定义多个新的属性或者修改现有属性,并且返回该对象

javascript
var obj = {
	_age: 18,
}

Object.defineProperties(obj, {
	name: {
		writable: true,
		value: 'mocha',
	},
	age: {
		get: function () {
			return this._age
		},
	},
})

五、对象的其他方法补充 ​

  • 获取对象的属性描述符

    • getOwnPropertyDescriptor

      javascript
      var obj = {
      	name: 'mocha',
      	age: 18,
      }
      
      console.log(Object.getOwnPropertyDescriptor(obj, 'name'))

      image-20230703205325591

    • getOwnPropertyDescriptors

      javascript
      var obj = {
      	name: 'mocha',
      	age: 18,
      }
      
      console.log(Object.getOwnPropertyDescriptors(obj))

      image-20230703205358591

  • 禁止对象扩展新属性:preventExtensions

    • 给对象添加新的属性会失败(在严格模式下会报错)

      javascript
      var obj = {
      	name: 'mocha',
      	age: 18,
      }
      
      Object.preventExtensions(obj)
      
      obj.address = '广州市'
      
      console.log(obj) // { name: 'mocha', age: 18 }
  • 密封对象,不允许配置和删除属性:seal

    • 实际是调用preventExtensions

    • 并且将现有属性的configurable设置为false

      javascript
      var obj = {
      	name: 'mocha',
      	age: 18,
      }
      
      Object.seal(obj)
      
      delete obj.name
      
      console.log(obj) // { name: 'mocha', age: 18 }
  • 冻结对象,不允许修改现有属性:freeze

    • 实际上是调用seal

    • 并且将现有属性的writable设置为false

      javascript
      var obj = {
      	name: 'mocha',
      	age: 18,
      }
      
      Object.freeze(obj)
      
      obj.name = 'latte'
      
      console.log(obj) // { name: 'mocha', age: 18 }