本系列主要整理前端面试中需要掌握的知识点。本节介绍defineProperty和proxy的区别。
Object.defineProperty()方法会直接在一个对象上定义一个新属性,或者修改一个对象现有的属性,并返回此对象。defineProperty通过get和set实现响应式。
function update() {
app.innerText = obj.foo
}
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
get() {
console.log(`get ${key}:${val}`);
return val
},
set(newVal) {
if (newVal !== val) {
val = newVal
update()
}
}
})
}
const obj = {}
defineReactive(obj, 'foo', '')
obj.foo = "foo" //可以触发响应式,因为触发了update函数,foo显示在了dom元素中。
function defineReactive(obj, key, val) {
// 在对象存在多个key情况下,需要进行遍历
observe(val)
Object.defineProperty(obj, key, {
get() {
console.log(`get ${key}:${val}`);
return val
},
set(newVal) {
if (newVal !== val) {
observe(newVal) // 新值是对象的情况
update()
}
}
})
}
// 在对象存在多个key情况下,需要进行遍历
function observe(obj) {
if (typeof obj !== 'object' || obj == null) {
return
}
Object.keys(obj).forEach(key => {
defineReactive(obj, key, obj[key])
})
}
const obj = {
foo: "foo",
bar: "bar"
}
observe(obj)
obj.foo = "new" // ok
delete obj.foo // no ok
obj.jar = 'xxx' // no ok
console.log(obj);
get ${key}:${val}
,如果触发set,页面的dom元素的text会发生更改,但是在进行删除和增加属性的时候,都没有触发过get和set,因此是没有触发响应式的。而给foo赋新值的时候,打印了get foo:foo
,此时就是触发了get。function reactive(obj) {
if (typeof obj !== 'object' && obj != null) {
return obj
}
// Proxy相当于在对象外层加拦截
const observed = new Proxy(obj, {
get(target, key, receiver) {
const res = Reflect.get(target, key, receiver)
console.log(`获取${key}:${res}`)
return res
},
set(target, key, value, receiver) {
const res = Reflect.set(target, key, value, receiver)
console.log(`设置${key}:${value}`)
return res
},
deleteProperty(target, key) {
const res = Reflect.deleteProperty(target, key)
console.log(`删除${key}:${res}`)
return res
}
})
return observed
}
const state = reactive({
foo: 'foo'
})
// 1.获取
state.foo // ok
// 2.设置已存在属性
state.foo = 'fooooooo' // ok
// 3.设置不存在属性
state.dong = 'dong' // ok
// 4.删除属性
delete state.dong // ok
// 5.嵌套对象
const state1 = reactive({
bar: { a: 1 }
})
// 设置嵌套对象属性
state1.bar.a = 10 // no ok
function reactive(obj) {
if (typeof obj !== 'object' && obj != null) {
return obj
}
// Proxy相当于在对象外层加拦截
const observed = new Proxy(obj, {
get(target, key, receiver) {
const res = Reflect.get(target, key, receiver)
console.log(`获取${key}:${res}`)
return typeof(res) == "object" ? reactive(res) : res
},
set(target, key, value, receiver) {
const res = Reflect.set(target, key, value, receiver)
console.log(`设置${key}:${value}`)
return res
},
deleteProperty(target, key) {
const res = Reflect.deleteProperty(target, key)
console.log(`删除${key}:${res}`)
return res
}
})
return observed
}