vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的,那么vue是如果进行数据劫持的,我们可以先来看一下通过控制台输出一个定义在vue初始化数据上的对象是个什么东西。
Object.defineProperty( )是用来做什么的?它可以来控制一个对象属性的一些特有操作,比如读写权、是否可以枚举,这里我们主要先来研究下它对应的两个描述属性get和set,如果还不熟悉其用法,
数据响应式即数据双向绑定,就是把Model绑定到view,当我们通过js修改Model,View会自动更新;若我们更新了View,Model的数据也会自动更新,这就是双向绑定。
vue2.0版本是利用了Object.defineProperty()这个方法重新定义对象获取属性值的get和设置属性值set的操作来实现的。
vue3.0版本采用了Es6的Proxy对象来实现。
我们先分别了解下defineProperty方法、Proxy对象。
defineProperty简言之,是定义对象的属性。
它其实并不是核心的为一个对象做数据绑定,而是给对象做属性标签。定义对象的属性。只不过是属性的get和set实现了响应式。
它可以来控制一个对象属性的一些特有操作,比如读写权、是否可以枚举,这里我们主要先来研究下它对应的两个描述属性get和set,如果还不熟悉其用法,
属性名 | 默认值 |
value | undefined |
get | undefined |
set | undefined |
writable | false |
enumerable | false |
configurable | false |
在平常,我们很容易就可以打印出一个对象的属性数据:
var person = { name: ‘小明‘ }; console.log(person.name); // 小明
如果想要在执行console.log(person.name)的同时,直接给书名加个书名号,那要怎么处理呢?或者说要通过什么监听对象 Book 的属性值。
这时候Object.defineProperty( )就派上用场了,代码如下:
var person = {} var name = ‘‘; Object.defineProperty(person, ‘name‘, { set: function (value) { name = value; console.log(‘你取了一个书名叫做‘ + value); }, get: function () { return ‘***‘ + name + ‘***‘ } }) Book.name = ‘vue权威指南‘; // 你取了一个书名叫做vue权威指南 console.log(Book.name); // ***vue权威指南***
我们通过Object.defineProperty( )设置了对象Book的name属性,对其get和set进行重写操作。
顾名思义,get就是在读取name属性这个值触发的函数,set就是在设置name属性这个值触发的函数。
所以当执行 Book.name = ‘vue权威指南‘ 这个语句时,控制台会打印出 "你取了一个书名叫做vue权威指南",
紧接着,当读取这个属性时,就会输出 "《vue权威指南》",因为我们在get函数里面对该值做了加工了。如果这个时候我们执行下下面的语句,控制台会输出什么?
console.log(Book);
结果:
接下来我们通过其原理来实现一个简单版的mvvm双向绑定代码。
<div id="app"> <input v-model="text" id="test"></input> <div id="show"></div> </div>
var obj = {
a:1,
b:2
};
var _value = obj.a
Object.defineProperty(obj,‘a‘,{
get:function(){
console.log("get方法")
return _value
},
set:function(newValue){
console.log("set方法")
_value = newValue
document.getElementById(‘test‘).value =_value
document.getElementById(‘show‘).innerHTML =_value
return _value
}
});
document.getElementById(‘test‘).addEventListener(‘input‘,function(e){
obj.a = e.target.value;
})
效果如下:
那么,在vue中从一个数据到发生改变的过程是什么?
注意点:
1)先拷贝一份数组原型链 2)定义一个方法总类
3)遍历数组,给数组原型链重新写方法,然后触发更新 dep.notify
proxy是什么?
https://www.jianshu.com/p/a831f76e5e71
Proxy对象用于定义基本操作的自定义行为,和defineProperty功能类似,只不过用法有些不同
两者比较:
Proxy好处:
1)数据若是多层,去除循环
2)不需要借助外部的value,不需要设置具体属性
3)不会污染原对象,Proxy只是代理了原对象
var obj = {
a:1,
b:2
};
var proxyObj = new Proxy(obj, {
get(target, key, receiver){ //我们在这里拦截到了数据
console.log("get方法",target,key,receiver)
return target[key]
},
set(target,key,value, receiver){ //改变数据的值,拦截下来额
console.log("set方法",target,key,value, receiver)
return Reflect.set(target,key,value)
}
})
console.log(proxyObj)
结果如下:
var proxyObj = new Proxy(obj, {
get:function(target, key, receiver){ //我们在这里拦截到了数据
console.log("get方法",target,key,receiver)
return true
},
set:function(target,key,value, receiver){ //改变数据的值,拦截下来额
console.log("set方法",target,key,value, receiver)
target[key]= value
document.getElementById(‘test‘).value= value
document.getElementById(‘show‘).innerHTML=value
return true
}
})
document.getElementById(‘test‘).addEventListener(‘input‘,function(e){
proxyObj.a = e.target.value;
})
defineProperty只能监听某个属性,不能对全对象监听,所以可以省去for in 提升效率
可以监听数组,不用再去单独对数组做操作
原文:https://www.cnblogs.com/renzm0318/p/12289415.html