概述
一.ObjectdefineProperty()
javascript有两种变化侦测的手段:Object.defineProperty()和ES6 的 Proxy;
vue2中使用的是Object.defineProperty(),vue3中使用的是Proxy。
Object.defineProperty()方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
//
把name放进data 打印出来
const data = {};
let name = "Vue";
//value 和 get方法不能共存,拦截了对于属性的访问,这样就相当于把数据劫持了
//Cannot both specify accessors and a value or writable attribute
Object.defineProperty(data,'name',{
get:function (){
console.log('get')
return name;
},
set:function(newVal){
console.log('set');
name = newVal;
//视图更新渲染
}
})
console.log(data.name)
data.name = '麦迪'
console.log(data.name)
二.基本的响应式实现
vue源码中有一个核心方法叫 defineReactive() ,使用Object.defineProperty()f方法;主要用于将**非响应式数据转换为响应式数据,**什么意思呢,就是说将没有被侦测的数据,转化为变侦测的数据。这个过程,我比较喜欢叫它数据劫持。
// 简单的没有嵌套的数据
const data = {
name:"李小龙",
age:33
};
//变成响应式数据
observer(data)
function observer(target){
if(typeof target !== 'object' || target === null){
return target;
}
// 循环数据的每一项
for(let key in target){
defineReactive(target,key,target[key]);
}
}
function defineReactive(target,key,value){
Object.defineProperty(target,key,{
get:function(){
return value;
},
set:function(newValue){
value = newValue;
console.log('更新视图')
}
})
}
data.name = '科比';
data.age = 39;
三.复杂对象的响应式实现
Observer定义好以后,数据为复杂对象时,我们在defineReactive中进行深度监听,observer(value),observer中有判断,不是对象会返回。
defineReactive 和 observer相互嵌套
const data = {
name:"李小龙",
age:33,
friend:{
friendName:"尤雨溪"
}
};
//变成响应式数据
observer(data)
function observer(target){
if(typeof target !== 'object' || target === null){
return;
}
// 循环数据的每一项
for(let key in target){
// console.log(key,target[key])
defineReactive(target,key,target[key]);
}
}
function defineReactive(target,key,value){
console.log(key,value)
// 深度监听
observer(value);
//defineReactive 和 observer相互嵌套
Object.defineProperty(target,key,{
get:function(){
return value;
},
set:function(newValue){
observer(newValue);
// 设置的时候也要监听
value = newValue;
console.log('更新视图')
}
})
}
// data.name = '科比';
// data.age = 39;
// data.friend.friendName = '刘龙斌';
// data.age = {number: 99 };
// data.age.number = 777;
delete data.age;
data.test = 'susu'
// 删除或者增加data的属性,不会触发视图的更新;
// vue2.0中Object.defineProperty没有办法处理属性删除和新增;
// 需要使用另外的方法 删除使用Vue.delete 新增使用Vue.$set,会更新视图
vue2.0中删除或者增加data的属性,不会触发视图的更新;y因为 Object.defineProperty没有办法处理属性删除和新增;需要使用另外的方法 删除使用Vue.delete 新增使用Vue.$set,会更新视图
四.数组的响应式实现
const oldArrayProto = Array.prototype;
const newArrProto = Object.create(oldArrayProto);
console.log('oldArrayProto', oldArrayProto);
// 要被改写的7个数组方法
const methodsNeedChange = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
];
methodsNeedChange.forEach(methodName => {
newArrProto[methodName] = function (){
console.log('更新视图---222')
oldArrayProto[methodName].call(this,...arguments)
}
}) // 这样改造下,push这些方法就可以触发更新视图,也可以执行原有的功能
// console.log('newArrProto', newArrProto);
//变成响应式数据
observer(data)
function observer(target) {
if (typeof target !== 'object' || target === null) {
return;
}
if(Array.isArray(target)){
target.__proto__ = newArrProto;
//将数组之前的原型替换为新的原型
}
// 循环数据的每一项
for (let key in target) {
defineReactive(target, key, target[key]);
}
}
Array是通过定义自己的数组方法去覆盖数组原型方法的方式去侦测数据的。那前提肯定就是数组调用这些方法去改变自己的时候,我们才能侦测到。
所以:
当数组不同这些方法,而是通过其他方法去更改数组时,我们依然无法得知。比如
arr[1] = 3 这样去修改,并没有调用数组方法,我们就无法得知数据发生了变化。
或者arr.length = 0去清空了数组,我们同样也是无法得知的。
所以这个问题,还是要到vue3中通过proxy去解决了。
最后
以上就是怕孤独山水为你收集整理的Vue数据响应式原理简单解释的全部内容,希望文章能够帮你解决Vue数据响应式原理简单解释所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复