Vue双向数据绑定原理-下

发布时间 2023-09-30 21:22:14作者: BNTang

Vue双向数据绑定原理-下这一篇文章主要讲解Vue双向数据绑定的原理,主要是通过Object.defineProperty()来实现的,这里我们手写Vue双向数据绑定的原理。

首先我提出一个需求,我的需求是,快速监听对象中所有属性的变化

首先得要有一个对象,对象的定义代码如下:

<script>
    let obj = {
        name: 'BNTang',
        age: 33
    };
</script>

然后我们需要监听这个对象中所有属性的变化,最最最简单的做法如下,这里我们可以使用Object.defineProperty()来实现,代码如下:

Object.defineProperty(obj, 'name', {
    get() {
        return 'BNTang';
    },
    set(newValue) {
    }
});

Object.defineProperty(obj, 'age', {
    get() {
        return 18;
    },
    set(newValue) {
    }
});

这样我们就可以监听到对象中所有属性的变化了,但是这样写的话,代码量太大了,如果有100个属性,那么就要写100次,这样的话,代码量太大了,所以我们需要写一个函数来实现这个功能(例如自定义类)。

博主这里采用的是自定义类的方式来实现,首先定义一个类,代码如下:

class Observer {
    
}

只要将需要监听的那个对象传递给Observer这个类,这个类就可以快速的给传入的对象的所有属性都添加get/set方法, 该类的主要功能就是给传入的对象的所有属性都添加get/set方法。

首先我定义了一个构造函数,绑定了一个形参,就是需要监听的对象,代码如下:

constructor(data) {
}

在然后我定义了一个 observer 方法,将需要监听的对象传递给 observer 方法,遍历取出传入对象的所有属性,给遍历到的属性都增加get/set方法,代码如下:

observer(obj) {
    if (obj && typeof obj === 'object') {
        for (let key in obj) {
        }
    }
}

在 for 循环中,我使用了 defineReactive 方法(自定义一个方法单独来处理),该方法的作用是给传入的对象的所有属性都添加get/set方法,代码如下:

defineReactive(obj, attr, value) {
    Object.defineProperty(obj, attr, {
        get() {
            return value;
        },
        set: (newValue) => {
            if (value !== newValue) {
                value = newValue;
                console.log('监听到数据的变化, 需要去更新UI');
            }
        }
    })
}

好了,现在我们已经定义了一个类,该类的主要功能就是给传入的对象的所有属性都添加get/set方法,那么我们就可以使用这个类了(Test 阶段),代码如下:

new Observer(obj);
obj.name = 'Example';

image-20230930210837470

查看打印结果,可以看到,我们已经监听到了数据的变化,但是这里有一个问题,就是我们只能监听到对象中已经存在的属性的变化,不能监听对象中属性的对象的属性的变化,例如下面的对象代码:

let obj = {
    name: {a: 'abc'},
    age: 33
};

就是对象中的属性值又是一个对象,而这个属性的对象的属性值发生改变,我们自定义的 Observer 是无法进行监听到的。所以我们需要对这个问题进行处理,我们需要对传入的对象进行递归处理,代码如下: