Object.defineProperty() - 1

58 阅读4分钟

定义:

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

语法:

Syntax:

Object.defineProperty(obj, prop, descriptor)

参数:

一共接受三个参数 obj, prop, descriptor;

  • obj: 要定义属性的对象
  • prop: 一个字符串或 Symbol,指定了要定义或修改的属性键。
  • desc: 配置项,一般是一个对象,有6个配置控制属性
    • value: 当前值, 默认:undefined;
    • get: 读取时内部调用的函数, 默认:undefined;
    • set: 写入时内部调用的函数, 默认:undefined;
    • writable: 是否可以重写, 默认:false;
    • enumerable: 是否可以被枚举,默认:false;
    • configurable: 是否可以再次修改配置项,以及可否删除,默认:false;
  • desc 6个配置项,组成了两类描述符:
    • 类1:数据描述符
      • 组成:
        • value
        • writable
        • enumerable
        • configurable
    • 类2:存取属性描述符(也叫 访问器描述符)
      • 组成:
        • get
        • set
        • enumerable
        • configurable

返回值:

传入函数的对象,其指定的属性已被添加或修改;

描述符详细介绍:

数据属性描述符:

  1. [[configurable]]:表示属性是否可以通过delete删除,是否可以修改特性,是否可以将它修改为存取属性

    • (1)当我们直接在一个对象上定义某个属性时,它的默认值是true
    • (2)而当我们通过属性描述符进行定义属性时,它的默认值是false
  2. [[enumerable]]:表示属性是否可以通过for-in或者Object.keys返回属性

    • (1)当我们直接在一个对象上定义某个属性时,他的默认值是true
    • (2)而当我们通过属性描述符进行定义属性时,他的默认值是false
  3. [[writable]]:表示是否可以修改属性

    • (1)当我们直接在一个对象上定义某个属性时,他的默认值是true
    • (2)而当我们通过属性描述符进行定义属性时,他的默认值是false
  4. [[value]]:属性的value值,当读取属性时会返回value,修改属性时会修改value

    • (1)默认情况下value是undefined

存取属性描述符:

  1. [[configurable]]:表示属性是否可以通过delete删除,是否可以修改特性,是否可以将它修改为存取属性

    • (1)当我们直接在一个对象上定义某个属性时,它的默认值是true
    • (2)而当我们通过属性描述符进行定义属性时,它的默认值是false
  2. [[enumerable]]:表示属性是否可以通过for-in或者Object.keys返回属性

    • (1)当我们直接在一个对象上定义某个属性时,他的默认值是true
    • (2)而当我们通过属性描述符进行定义属性时,他的默认值是false
  3. [[get]]:获取属性时执行的函数,默认为 undefined

  4. [[set]]:设置或者修改属性值时执行的函数,默认为 undefined

属性描述符的冲突

[[value]][[writable]][[get]][[set]] 这两对不能同时出现;

Demo:

// Demo1: value
let Person = {}

Object.defineProperty(Person, 'name', { value: 'Jack' })
console.log('- Person.name ->: ',Person.name)
console.log('- Object.getOwnPropertyDescriptors(Person) ->: ', Object.getOwnPropertyDescriptors(Person))

Person.name = 'Leo'
console.log('- Person.name ->: ',Person.name) // Jack; 因为默认 wriable: false;

console.log('- Object.assign({}, Person) ->', Object.assign({}, Person)) // {}; 因为默认 enumerable: false;
console.log('- {...Person} ->: ',{...Person}) // {}; 因为默认 enumerable: false;

delete Person.name 
console.log('- Person.name ->: ',Person.name) // Jack; delete 未生效;因为默认 configurable: false;
Object.defineProperty(Person, 'name', { value: 'Leo' })
console.log('- Person.name ->: ',Person.name) // TypeError: Cannot redefine property: name;  因为默认 configurable: false;
// Demo2: writable
let Person = {}

Object.defineProperty(Person, 'name', { value: 'Jack', writable: true })
Person.name = 'Leo'
console.log('- Person.name ->: ',Person.name) // Leo; 因为定义 Person.name 属性可以被重写(writeable: true);
// Demo3: enumerable
let Person = {}

Object.defineProperty(Person, 'name', { value: 'Jack', enumerable: true })
console.log('- {...Person} ->: ',{...Person}) // { name: 'Jack' }; 因为定义了 Person.name 属性可以被枚举(enumerable: true);
Object.defineProperty(Person, 'age', { value: 20, enumerable: false })
console.log('- {...Person} ->: ',{...Person}) // { name: 'Jack' }; 因为定义了 Person.age 属性不可以被枚举;
Object.defineProperty(Person, 'sex', { value: '男', enumerable: true })
console.log('- {...Person} ->: ',{...Person}) // { name: 'Jack', sex: '男' }; 因为定义了 Person.sex 属性可以被枚举(enumerable: true);
// Demo4: configurable
let Person = {}

Object.defineProperty(Person, 'name', { value: 'Jack', configurable: true })
console.log('- Person.name ->: ',Person.name) // Jack
Object.defineProperty(Person, 'name', { value: 'Leo' })
console.log('- Person.name ->: ',Person.name) // Leo; 因为默认设置了 configurable: true; 属性可以被重新定义;
delete Person.name
console.log('- Person.name ->: ',Person.name) // undefined; 因为默认设置了 configurable: true; 属性可以被删除;
// Demo5: getter  setter
let Person = {}

Object.defineProperty(Person, 'name', { 
  value: 'Jack',
  get () {},
  enumerable: false,
  configurable: false
})
console.log('- Person.name ->: ',Person.name) 
// TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute; 
// 因为 [[value]] 、[[writable]] 和 [[get]]、[[set]] 这两对不能同时出现
// Demo6: getter  setter
let Person = {}

Object.defineProperty(Person, 'name', { 
  get () {},
  set () {},
  enumerable: false,
  configurable: false
})
console.log('- Person.name ->: ',Person.name) // undefined; 因为 get 没有设置返回值;
Person.name = 'Leo'
console.log('- Person.name ->: ',Person.name) // undefind; 因为 set 没有设置数据操作, get 没有设置返回值;
// Demo7: getter  setter
let Person = {}

let nameValue = 'Jack'
Object.defineProperty(Person, 'name', { 
  get () {
    return nameValue
  },
  set (newValue) {
    nameValue = newValue
  },
  enumerable: false,
  configurable: false
})
console.log('- Person.name ->: ',Person.name) // Jack; 因为 get 有返回值 nameValue;
Person.name = 'Leo'
console.log('- Person.name ->: ',Person.name) // Leo; 因为 set 对nameValue做了赋值,get 返回被赋值的 nameValue;