【JS】Object.defineproperty方法

前言

通常情况下,直接给对象添加属性和方法即可,但是Object.defineproperty()会更加强大。

var stu = new Person
stu.name = "张三"  // 添加属性
stu.say = function(){}  // 添加方法

Object.defineProperty()的作用就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性。它也是vue2的响应式原理。

语法

Object.defineProperty(obj, prop, desc)

参数

  • obj: 需要定义属性的当前对象
  • prop: 当前需要定义的属性名 「String、Symbol类型」
  • desc属性描述符,通过它来限制属性的读写行为

属性描述符

  • value:设置属性的值
  • writable:值是否可以重写,默认值为false
  • set:目标属性设置值的方法
  • get:目标属性获取值的方法
  • enumerable:目标属性是否可以被枚举(是否可以遍历),默认值为false
  • configurable:目标属性是否可以被删除是否可以再次修改,默认值为false

属性描述符分为两种:「数据描述符」和「存取描述符」。

其中value、writable为数据描述符,get、set为存取描述符,configurable 和 enumerable不受限制。

数据描述符(value、writable):

value:属性值
writable:是否可以修改值,默认为false

let person = {
    name: "张三",
}

Object.defineProperty(person, 'age', {
    value: 18,      // 设置属性值
    writable:true,  // 是否可修改,默认为false
})

console.log(person.age) // 18
person.age = 20
console.log(person.age) // 20

如果不写 writable 或 writable:false,看到控制台的打印未发生改变
【JS】Object.defineproperty方法_第1张图片

存取描述符(get、set):

get:当有人读取 person的prop时,get函数(getter)就会被调用,且返回值就是 prop 的值
set:当有人修改 person的prop时,set函数(setter)就会被调用,且会收到修改的具体值

let person = {
    name: "张三",
}

let num = 18

Object.defineProperty(person, 'age', {
  get: function () {
    console.log('有人操作对象了');
    return num
  },
  set: function (value) {
    console.log('值被修改了,value:', value);
    num = value
  },
})

读取prop,触发get函数

person.age    // 触发get函数(getter)

【JS】Object.defineproperty方法_第2张图片
修改prop,触发set函数

person.age = 20   // 触发set函数(setter)

【JS】Object.defineproperty方法_第3张图片

同时定义数据描述符和存储描述符会报错

【JS】Object.defineproperty方法_第4张图片

在这里插入图片描述

configurable 和 enumerable描述符

这两个属性描述符既可以与「数据描述符」配合使用,也可以与「存储描述符」配合使用。

configurable描述符

表示是否能再次「修改」或「删除」该属性的属性描述符,布尔值(默认为false)。
设为true时,才能再次修改该属性的属性描述符,同时该属性也能从对应的对象上被删除。
一般使用Object.defineProperty时,要设置为true,因为需要去更改这些键值。

删除

不设置configurable(为false)时,无法删除

let person = {
	name:"张三"
}

Object.defineProperty(person, 'age', {
  value: 23,
})
delete person.age
console.log(person.age) // 23

configurable: true时,可以删除

let person = {
	name:"张三"
}

Object.defineProperty(person, 'age', {
  value: 23,
  configurable: true,  // 是否可以被删除或修改
})
delete person.age
console.log(person.age) // undefined
修改

属性值的修改有两种方式,一种是赋值的形式object.prop = xxx,另一种是通过再次属性定义Object.defineProperty()并为同一prop重新设置value的方式。

这里所说的「修改」不同于上文说的「数据描述符」writable: true 指是否可以修改属性值,而是,是否可以通过属性定义的方式修改描述符

configurable为true,可以修改。
let person = {
	name:"张三"
}
Object.defineProperty(person, 'age', {
  value: 23,
  writable: false, // 这里为false只是禁止通过直接赋值的形式修改属性值
  configurable: true,  // 是否可以被删除或修改
})


// 通过属性定义的方式修改描述符value
Object.defineProperty(person, 'age', {
  value: 18 // 这里重新定义了属性值,因为 configurable 为 true,所以可以修改
})
console.log(person.age); // 18


// 通过赋值的形式修改值,由于writable为false,所以不可修改
person.age = 20
console.log(person.age); // 18 
相反,为false时,无法二次修改。
let person = {
	name:"张三"
}
Object.defineProperty(person, 'age', {
  value: 23,
  writable: true,
  configurable: false,  // 是否可以被删除或修改
})

// 通过属性定义的方式修改描述符value
Object.defineProperty(person, 'age', {
  value: 18 // 这里重新定义了属性值,因为 configurable 为 true,所以可以修改
})
console.log(person.age); // 18


// 通过赋值的形式修改值,由于writable为true,所以可以修改
person.age = 20
console.log(person.age); // 20

总结

  1. configurable: false 时,不能删除当前属性,且不能重新配置当前属性的描述符
  2. configurable: true时,可以删除当前属性,可以配置当前属性所有描述符。
  3. 不要混淆writable和configurable,writable指是否可以通过,configurable是指是否可以以属性定义的方式修改属性值。

enumerable描述符

表示属性是否可以被枚举(遍历),布尔值(默认为false)。

let person = {
	name:"张三"
}

Object.defineProperty(person, 'age', {
  value: 23,
})
console.log(person.age)  // 23

上述代码,即使设置了age属性,并且也可以取到age的值,但是直接打印person,并未发现新增的age属性,结果如下:
在这里插入图片描述
使用 for…in 遍历,或者 Object.keys方法 也无法读取新增的age属性

for (let key in person) {
  console.log(key)  // name
}

console.log(Object.keys(person))  // ['name']

【JS】Object.defineproperty方法_第5张图片

想让新增属性也可以被遍历,将 enumerable描述符 设置为true即可

let person = {
	name:"张三"
}

Object.defineProperty(person, 'age', {
  value: 23,
  enumerable: true,  // 是否可枚举(遍历)
})

console.log(person);
for (let key in person) {
  console.log(key) 
}
console.log(Object.keys(person));

如此发现,新增属性age属性可遍历
【JS】Object.defineproperty方法_第6张图片

注意

  • 数据描述符(value、writable)和 存取描述符(get、set),不允许同时使用,否则会报错,configurable 和 enumerable不做限制。

  • get 和 set不必要同时存在,也可以单独配置。

你可能感兴趣的:(JavaScript,面试题,javascript,前端,开发语言,ecmascript)