Vue的双向数据绑定是如何实现的呢
本篇文章将会通过一些小案例以及基础必备知识进行讲解,如Object.defineProperty。
1 Object.defineProperty
Object.defineProperty(obj,prop,descriptor)
参数obj,表示要定义属性的对象
参数prop,表示要定义的属性
参数descriptor,要定义或修改的属性描述符
返回值,是被传递给函数的对象
get属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数。该函数的返回值会被用作属性的值。默认为 undefined。
set属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值)。默认为 undefined。
详细信息请查看MDN
1.1 基本使用
<body>
<script>
let data = {}
let name = 'Vue'
//拦截data对象的name属性的访问
Object.defineProperty(data,'name',{
//访问属性执行对应的函数
get: function(){
console.log('get')
return name
},
set: function(val){
console.log('set')
name = val
//可以做渲染视图的工作
}
})
console.log(data.name)
data.name = 'LX'
console.log(data.name)
</script>
</body>
2 利用Object.defineProperty实现双向数据绑定
<body>
姓名:<span id="spanName"></span>
<br>
<input type="text" id="inpName">
<script>
let obj = {
name: ''
}
let newObj = JSON.parse(JSON.stringify(obj)) //最好深克隆
Object.defineProperty(obj,'name',{
get(){
return newObj.name //声明一个newObj使用在此处的,因为getter不能够再次调用当前值,否则会执行不下去
},
set(val){
if(val !== newObj.name){
newObj.name = val
}
observe()
}
})
function observe(){
spanName.innerHTML = obj.name
inpName.value = obj.name
}
observe()
setTimeout(function(){
obj.name = "lx"
},1000)
//监听视图的改变
inpName.oninput = function(){
obj.name = this.value
}
/*1.对原始数据克隆
2.需要分别给对象中的每一个属性监听设置*/
</script>
</body>
执行结果如下图
3 利用Proxy实现双向数据绑定
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)
语法:
const p = new Proxy(target, handler)
参数target:要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
参数handler:一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。
handler.get()属性读取操作的捕捉器。
handler.set()属性设置操作的捕捉器。
详细信息请查看MDN
<script>
//第二种,使用Proxy,不需要克隆,也不需要给每个对象属性单独设置
let obj = {
name: ''
}
obj = new Proxy(obj,{
get(target,prop){ //target是需要操作的对象,prop是该对象的属性
console.log('A')
return target[prop]
},
set(target,prop,val){
console.log('B')
target[prop] = val
observe()
}
})
function observe(){
spanName.innerHTML = obj.name
inpName.value = obj.name
}
observe()
setTimeout(function(){
obj.name = "lx"
},1000)
//监听视图的改变
inpName.oninput = function(){
obj.name = this.value
}
</script>
执行结果相同。
4 Object.defineProperty与Proxy的区别
1.Object.defineProperty() 的问题主要有三个:
不能监听数组的变化,需要重写数组方法,利用Array.prototype。
必须遍历对象的每个属性,无法监听到对象删除属性或者新增属性。
必须深层遍历嵌套的对象。
2.Proxy
可以直接监听对象而非属性。
可以直接监听数组的变化。
可以嵌套。
- 本文作者: étoile
- 版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!