通过观察者模式初步了解Object.defineProperty 和 proxy 区别
Object.defineProperty()
和 Proxy
都是 JavaScript 中用于对象属性操作的工具。
具体的文档详解可以去查看MDN
Object.defineProperty()
可以定义一个对象的新属性或修改一个对象的现有属性。它的语法如下:
Object.defineProperty(obj, prop, descriptor)
参数说明:
obj
:要在其上定义属性的对象。prop
:要定义或修改的属性的名称。descriptor
:将被定义或修改的属性的描述符对象。
其中,descriptor
对象可以指定以下属性:
value
:属性的值。writable
:表示属性是否可写。enumerable
:表示属性是否可枚举。configurable
:表示是否可以删除属性或修改属性描述符。
Proxy
允许在目标对象之前架设一个拦截器,从而改变底层的实现方式。拦截器是一个对象,其中定义了当试图访问目标对象的属性时要进行的操作。它的语法如下:
new Proxy(target, handler)
参数说明:
target
:要使用 Proxy 包装的对象。handler
:一个对象,其属性是内部方法(例如 get、set、apply 等),用于拦截操作。
通过 Proxy
,您可以拦截访问对象属性、修改对象属性、添加和删除属性等操作,并执行自定义代码。
这两个工具在实现方法上有所不同,Object.defineProperty()
是原生的 JavaScript 方法,而 Proxy
是在 ECMAScript 6 中引入的新功能。Object.defineProperty()
更适用于单个属性的修改,而 Proxy
则更适合对整个对象的访问或修改进行拦截和控制。
Object.defineProperty 实现观察者模式
<div></div>
<script>
// 创建一个观察者
function observer(target) {
const div = document.querySelector('div')
const ob = {}
const props = Object.keys(target)
for(const prop of props){
Object.defineProperty(ob,prop,{ //对象静态方法会直接在一个对象上定义一个新属性或修改其现有属性,并返回一个新对象。
set(val){
target[prop] = val
render()
},
get(){
return target[prop]
},
enumerable:true,
})
}
render()
function render(){
let html = ''
for(const b of Object.keys(ob)){
html += `
<p><span>${b}:${ob[b]}</span></p>
`
}
console.log(html)
console.log(div)
div.innerHTML = html
}
return ob
}
const obj = observer({
a:1,
b:2
})
console.log(obj)
setTimeout(() => {
obj.a = 1111
console.log(obj.a)
obj.c = 3
console.log(obj)
}, 1000);
</script>
Proxy 实现观察者模式
<div></div>
<script>
// 创建一个观察者
function observer(target) {
const div = document.querySelector('div')
const proxy = new Proxy(target,{
set(target,prop,value){ // 通过proxy 用新的set 代替 原 set属性
Reflect.set(target,prop,value)
render()
},
get (target,prop){ // 通过proxy 用新的get 代替 原 get属性
return Reflect.get(target,prop)
}
})
render()
function render(){
let html = ''
for(const b of Object.keys(proxy)){
html += `
<p><span>${b}:${proxy[b]}</span></p>
`
}
console.log(html)
console.log(div)
div.innerHTML = html
}
return proxy
}
const obj = observer({
a:1,
b:2
})
console.log(obj)
setTimeout(() => {
obj.a = 1111
console.log(obj.a)
obj.c = 3
console.log(obj)
}, 1000);
</script>
总结
从上面两个代码分析来看,defineProperty
基于原对象 赋予一个新对象(我们这边为了创建一个新对象保持原有对象这么实现,本身defineProperty是直接返回他处理的那个对象,并不会生成新的对象
),并且修改原有属性setter,getter。最后返回新的对象,修改新对象或者原对象的同时,另一个对象的值也被修改,因为他们两个人指向同一个内存空间。而proxy
可以这么理解在原有对象上包了一层,调用对象属性,proxy负责去实现代理已有的属性方法,目前官方文档给出其实不算很多。但是针对日常开发搓搓有余了。性能提一嘴,defineProperty
正常使用中,他需要创建新的对象进行观察,这时候造成了内存泄漏,相对于proxy
就浪费很多性能
转载自:https://juejin.cn/post/7246310077233135653