2019.10.5日发布了Vue3.0,如今2020年了,估计Vue3.0正式版也快出来了。html
2.0跟3.0的变化也挺大的,vue
Vue 2.0node
Vue2.0实现MVVM(双向数据绑定)的原理是经过 Object.defineProperty 来劫持各个属性的setter、getter,在数据变更时发布消息给订阅者,触发相应的监听回调。react
Vue官网也给出了解释:算法
Vue 3.0 实现响应式基于ES6: Proxychrome
下面是基于Object.defineProperty ,一步步实现简单版Vue2.0。数组
因为Object.defineProperty 没法监听数组,因此数组类型实现响应式,须要处理。 判断若是是数组类型,就重写数组的原型方法('push','pop','shift',unshift)浏览器
// 从新定义数组原型,Object.defineProperty不具有监听数组的方法
const oldArrayProperty = Array.prototype;
const arrProto = Object.create(oldArrayProperty);
["push","pop","shift","unshift","splice"].forEach(
methodName =>
(arrProto[methodName] = function() {
updateView();
oldArrayProperty[methodName].call(this, ...arguments);
})
)
复制代码
将传入的data属性进行深度监听,判断是对象仍是数组。ide
function observer(target){
if(typeof target !== 'object' || target === null){
return target
}
// 若是是数组类型,重写数组原型的方法("push","pop","shift","unshift","splice")
if(Array.isArray(target)){
target.__proto__ == arrProto;
}
// 若是是对象,遍历对象全部的属性,并使用Object.defineProperty把这些属性所有转为getter/setter
for(let key in target){
defineReactive(target,key,target[key])
}
}
复制代码
核心API Object.defineProperty,将传入属性转为 getter/setter函数
function defineReactive(target, key, value){
// 若是对象有更多的层级,再次调用observer监听方法,实现深层次的监听。
observer(value);
Object.defineProperty(target, key, {
get(){
return value;
},
set(newValue){
// 设置值的时候也须要深度监听
observer(value);
if(newValue !== value){
value = newValue;
// 数据驱动视图,若是数据改变,就调用视图更新的方法。对应到Vue中是执行VDOM
updateView();
}
}
})
}
复制代码
数据更新会触发视图更新,这是MVVM的绑定原理,这就会涉及到Vue的 template 编译为 render 函数,在执行 Virtual Dom, Diff算法, Vnode等 这些东西了。
function updateView(){
console.log('视图更新')
}
复制代码
5.使用
const data = {
name: "zhangsan",
age: 20,
info: {
address: "北京" // 须要深度监听
},
nums: [10, 20, 30]
};
observer(data);
复制代码
Vue3.0基于Proxy来作数据大劫持代理,能够原生支持到数组的响应式,不须要重写数组的原型,还能够直接支持新增和删除属性, 比Vue2.x的Object.defineProperty更加的清晰明了。
核心代码(很是少)
const proxyData = new Proxy(data, {
get(target,key,receive){
// 只处理自己(非原型)的属性
const ownKeys = Reflect.ownKeys(target)
if(ownKeys.includes(key)){
console.log('get',key) // 监听
}
const result = Reflect.get(target,key,receive)
return result
},
set(target, key, val, reveive){
// 重复的数据,不处理
const oldVal = target[key]
if(val == oldVal){
return true
}
const result = Reflect.set(target, key, val,reveive)
return result
},
// 删除属性
deleteProperty(target, key){
const result = Reflect.deleteProperty(target,key)
return result
}
})
复制代码
使用
const data = {
name: "zhangsan",
age: 20,
info: {
address: "北京" // 须要深度监听
},
nums: [10, 20, 30]
};
复制代码
直接这样就能够了,也不须要声明,Proxy直接会代理监听data的内容,很是的简单方便,惟一的不足就是部分浏览器没法兼容Proxy,也不能hack,因此目前只能兼容到IE11。
可直接将代码复制到chrome浏览器的控制台,直接调试打印。
复制代码
Vue2.0
function defineReactive(target, key, value) {
//深度监听
observer(value);
Object.defineProperty(target, key, {
get() {
return value;
},
set(newValue) {
//深度监听
observer(value);
if (newValue !== value) {
value = newValue;
updateView();
}
}
});
}
function observer(target) {
if (typeof target !== "object" || target === null) {
return target;
}
if (Array.isArray(target)) {
target.__proto__ = arrProto;
}
for (let key in target) {
defineReactive(target, key, target[key]);
}
}
// 从新定义数组原型
const oldAddrayProperty = Array.prototype;
const arrProto = Object.create(oldAddrayProperty);
["push", "pop", "shift", "unshift", "spluce"].forEach(
methodName =>
(arrProto[methodName] = function() {
updateView();
oldAddrayProperty[methodName].call(this, ...arguments);
})
);
// 视图更新
function updateView() {
console.log("视图更新");
}
// 声明要响应式的对象
const data = {
name: "zhangsan",
age: 20,
info: {
address: "北京" // 须要深度监听
},
nums: [10, 20, 30]
};
// 执行响应式
observer(data);
复制代码
Vue3.0
const proxyData = new Proxy(data, {
get(target,key,receive){
// 只处理自己(非原型)的属性
const ownKeys = Reflect.ownKeys(target)
if(ownKeys.includes(key)){
console.log('get',key) // 监听
}
const result = Reflect.get(target,key,receive)
return result
},
set(target, key, val, reveive){
// 重复的数据,不处理
const oldVal = target[key]
if(val == oldVal){
return true
}
const result = Reflect.set(target, key, val,reveive)
console.log('set', key, val)
return result
},
deleteProperty(target, key){
const result = Reflect.deleteProperty(target,key)
console.log('delete property', key)
console.log('result',result)
return result
}
})
// 声明要响应式的对象,Proxy会自动代理
const data = {
name: "zhangsan",
age: 20,
info: {
address: "北京" // 须要深度监听
},
nums: [10, 20, 30]
};
复制代码