Responsiveness of vue for interview questions


foreword

The study records for the interview may not be deep enough or even have mistakes. Please forgive me, and let us make progress together.


1. What is Responsive?

My personal simple understanding is that when the data changes, it can automatically perform certain operations we need. In vuethe middle, after we render the data to the page for the first time, if we modify the data later, the page will also be automatically updated. Obviously, it vuehelps us complete the responsiveness.
我们先来讲述vue2的响应式实现。
后面在讲述vue3,因为他们实现的原理有区别。

Two, Object.defineProperty

First of all, we need to understand Object.defineProperty()that this method can help us hijack the properties on the object, which is the core content of implementing responsiveness.

Let's use it first Object.defineProperty().

		const data = {
    
    };
		let name = 'xiacan';
		/**
		 * 第一个参数: 要监听的对象
		 * 第二个参数: 要监听的属性
		 * 第三个参数:  一个有get函数和set函数的对象
		 */
		Object.defineProperty(data,"name",{
    
    
			get(){
    
    
				console.log("name属性被获取啦!");
				//返回值 就是我们data[name] 获取到的值
				return name;
			},
			set(value) {
    
    
				// value 就是 我们设置name属性时候赋值的值
				console.log("name属性被赋新值了:",value);
				name = value;
			}
		})
		console.log(data.name);
		data.name = 'xiazai';
		console.log(data.name);

Result after execution:
insert image description here
Is it very simple? We have completed the monitoring of object properties. When the object is used and modified, we can already do the operations we need.

2. Simple simulation of vue

Above we learned how to monitor objects, let's simply simulate vue.

//模拟视图更新
function updateView(){
    
    
	console.log("视图更新啦!");
}

// 具体进行数据监听的函数
function definePy(target, key, value){
    
    
	Object.defineProperty(target, key, {
    
    
		get() {
    
    
			//直接返回当前值
			return value;
		},
		set(newValue) {
    
    
			//判断是否是修改为新值,否则不更新视图
			if(newValue === value) return; 
			value = newValue;
			//更新视图
			updateView();
		}
	})
}

//监听数据函数
function observer(target){
    
    
	//判断如果是基本类型就不监听
	if(typeof target !== 'object' || target === null ) return target;
	
	//我们循环对象的所有属性
	for(let key in target){
    
    
		//监听每个属性 将对象 当前属性 当前属性值传入
		definePy(target,key,target[key])
	}
	
}

//初始数据
const data = {
    
    
	name: 'xiacan',
	age: 22
}
//开始监听数据
observer(data)

data.name = 'xiazai';
console.log(data.name);

Running screenshot:
insert image description here
In this way, we have successfully and simply simulated the responsiveness of vue.
但是我们还不够,不能对data进行深程度的监听。

3. In-depth monitoring

We deepen the initial data hierarchy:

//初始数据
const data = {
    
    
    name: 'xiacan',
    age: 22,
    like:{
    
    
        one:'xi'
    }
}
//开始监听数据
observer(data)
data.like.one = 'ai';

Run it:
insert image description here
obviously, like对象属性the transform is not detected.

We further optimized and were able to proceed 深度监听数据.

//模拟视图更新
function updateView(){
    
    
    console.log("视图更新啦!");
}

// 具体进行数据监听的函数
function definePy(target, key, value){
    
    
    // 进行深度循环
    observer(target[key]);
    
    Object.defineProperty(target, key, {
    
    
        get() {
    
    
            //直接返回当前值
            return value;
        },
        set(newValue) {
    
    
            //判断是否是修改为新值,否则不更新视图
            if(newValue === value) return;
            // 进行深度循环,再有新值时候
            observer(newValue);
            
            value = newValue;
            //更新视图
            updateView();
        }
    })
}

//监听数据函数
function observer(target){
    
    
    //判断如果是基本类型就不监听 同时返回
    if(typeof target !== 'object' || target === null ) return target;

    //我们循环对象的所有属性
    for(let key in target){
    
    
        //监听每个属性 将对象 当前属性 当前属性值传入
        definePy(target,key,target[key]);
    }

}

//初始数据
const data = {
    
    
    name: 'xiacan',
    age: 22,
    like:{
    
    
        one:'xi',
        two:'22'
    }
}
//开始监听数据
observer(data)

data.like.one = 'ai';
data.like.two = {
    
    
    a:1
};
data.like.two.a = 2;


Run it:
insert image description here

Before we start hijacking the data attribute, we can monitor the current attribute once to achieve in-depth monitoring, because we have written the end condition before, that is, if it is a basic type, it will not monitor and return at the same time, so that it will not die. cycle.
Then it is necessary 赋新值to perform a deep cycle every time the attribute is used, because it is possible to assign an object so that we can monitor changes.

We still need to carry out the next step of optimization, which is to realize the correctness 数组的监听.

Four, monitor array

Let's take a look at listening to the array first:

//初始数据
const data = {
    
    
    name: 'xiacan',
    age: 22,
    like:{
    
    
        one:'xi',
        two:'22'
    },
    num: [1, 2, 3]
}
//开始监听数据
observer(data)

data.num[0] = 11
data.num.push(4)

Run it:
insert image description here
Obviously, the original data change of the array can be monitored, but it cannot be monitored when the method of the array is executed.

We want to realize the monitoring of the array, we need to modify the prototype of the array, define the method on the prototype, let us realize the change of monitoring the array.

//模拟视图更新
function updateView(){
    
    
    console.log("视图更新啦!");
}


//创建一个新对象,原型执行数组的原型,但是不会干扰原来的原型
const newArr = Object.create(Array.prototype);
//数组方法太多了,我们选几个常见的修改
[ 'push', 'unshift', 'shift', 'pop' ].forEach(newFunName =>{
    
    
    newArr[newFunName] = function () {
    
    
        //更新视图
        updateView();
        //执行数组原型上原始的方法
        Array.prototype[newFunName].call(this, ...arguments)
    }
})
// 具体进行数据监听的函数
function definePy(target, key, value){
    
    
    // 进行深度循环
    observer(target[key]);

    Object.defineProperty(target, key, {
    
    
        get() {
    
    
            //直接返回当前值
            return value;
        },
        set(newValue) {
    
    
            //判断是否是修改为新值,否则不更新视图
            if(newValue === value) return;

            // 进行深度循环,再有新值时候
            observer(newValue);

            value = newValue;
            //更新视图
            updateView();
        }
    })
}

//监听数据函数
function observer(target){
    
    
    //判断如果是基本类型就不监听 同时返回避免死递归
    if(typeof target !== 'object' || target === null ) return target;

    //判断如果是数组,我们就修改原型为我们新建的
    if (Array.isArray(target)){
    
    
        target.__proto__  = newArr;
    }

    //我们循环对象的所有属性
    for(let key in target){
    
    
        //监听每个属性 将对象 当前属性 当前属性值传入
        definePy(target,key,target[key]);
    }

}

//初始数据
const data = {
    
    
    name: 'xiacan',
    age: 22,
    like:{
    
    
        one:'xi',
        two:'22'
    },
    num: [1, 2, 3]
}
//开始监听数据
observer(data)

data.num.push(4);
data.num.pop();

Run it:
insert image description here
Why do we need to modify the array prototype, because we can't pollute the global array prototype, so we define a new prototype by ourselves, and then modify the method of the array, and add the method of updating the view in it, this It is also the implementation method of monitoring arrays in vue, and then when we start to monitor data data, we first judge, if it is an array, we change the prototype of the current object to our new prototype.

Summarize

We have roughly simulated the responsiveness of vue, and we can find that 新增属性和删除属性we cannot monitor the object, so there are other special methods in vue to complete it. For arrays, we need to re-modify the prototype to implement monitoring. In vue2, in-depth monitoring is done in a continuous cycle. If there are many data levels, the speed will become slower. After vue3 uses proxy, the speed will be improved, and it also supports the addition and deletion of detection attributes, as well as monitoring arrays, and the article will be updated and recorded after subsequent learning.

Guess you like

Origin blog.csdn.net/xia_zai_ya/article/details/130154547