# Object.defineProperty
简介
Object.defineProperty()
方法允许通过属性描述对象,定义或修改一个属性,然后返回修改后的对象。用法
Object.defineProperty(object, propertyName, attributesObject)
接受三个参数:- object:属性所在的对象
- propertyName:字符串,表示属性名
- attributesObject:属性描述对象
属性描述对象
属性描述符有两种主要形式:数据描述符和存取描述符,一个描述符只能是这两者其中之一。- 数据描述符
{ configurable: boolean // 当该属性为true时,该属性的描述符才能够被改变,默认false enumerable: boolean // 当该属性为true时,该属性才会出现在对象的枚举属性中,默认false value: any // 该属性对应的值,可以是任何有效的JavaScript值(数值,对象,函数等),默认undefined writable: boolean // 当该属性为true时,该属性的值才能被改变,默认false }
- 存取描述符
{ configurable: boolean enumerable: boolean get: function // 属性的getter函数,当访问该属性时,会调用此函数。 set: function // 属性的setter函数,当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值) }
一个例子
const person = {
name: 'lisi',
age: 24,
say: function() {
console.log(`hello, i am ${this.name}`)
},
body: {
height: 170,
weight: 60
}
}
function observe(obj) {
Object.keys(obj).map(key => {
reactive(obj, key, obj[key])
})
}
function reactive(obj, key, value) {
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
set(newValue) {
console.log(`set ${key} = ${newValue}`)
value = newValue
},
get() {
console.log(`get ${key} value`)
return value
}
})
}
observe(person)
person.age // get age value
person.age = 48 // set age = 48
person.body.height = 180 // 没有触发set
person.childCount = 5 // 没有触发set
person.childCount // 没有触发get
const skill = ['打篮球', '踢足球', '羽毛球']
observe(skill)
skill[0] // get 0 value
skill[0] = '乒乓球' // set 0 = '乒乓球'
skill.push('乒乓球') // 没有触发set
- 特点
- 是对对象属性的劫持。
- 无法检测到新增/删除属性变化。
- 只能检测get和set。
- 对于嵌套的对象无法检测,除非我们深度遍历。
- 无法检测到数组的某些变化,因为对于数组来说,劫持的属性就是索引下标,如果我们操作未劫持的下标,就无法检测到变化。
# Proxy
- 简介
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义。 - 用法
const p = new Proxy(target, handler)
接受两个参数:- target, 要使用 Proxy 包装的目标对象。
- handler 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。
- 例子
const person = {
name: 'lisi',
age: 24,
say: function() {
console.log(`hello, i am ${this.name}`)
},
body: {
height: 170,
weight: 60
}
}
const handler = {
get: function(target, property, receiver) {
console.log(`get ${property}`)
return Reflect.get(target, property, receiver)
},
set: function(target, property, value, receiver) {
console.log(`set ${property} = ${value}`)
return Reflect.set(target, property, value, receiver)
}
}
const p = new Proxy(person, handler)
p.age // get age
p.age = 48 // set age = 48
p.body.height = 180 // 没有触发set
p.childCount = 5 // set childCount = 5
p.childCount // get childCount
const skill = ['打篮球', '踢足球', '羽毛球']
const s = new Proxy(skill, handler)
s[0] // get 0 value
s[0] = '乒乓球' // set 0 = '乒乓球'
s.push('乒乓球') // get push-->get length--> set 3 = 乒乓球--> set length = 4
s.length // get length
- 特点
- 是对对象的劫持。
- 对于嵌套的对象无法检测,除非我们深度遍历。
- 可以检测到新增/删除属性变化。
- 可以检测到13种操作,比Object.defineProperty强大很多。
- 可以检测到数组的所有变化。
# Reflect
- 简介 Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与proxy handlers的方法相同。
- 特点
- Reflect的所有属性和方法都是静态的。
- 并非一个构造函数,所以不能通过new运算符对其进行调用。