然后 我们来学一下defineReactive函数
defineReactive其实是一个要声明的函数 基本都是作为一个响应式函数 因为vue的使用比较经典 因此 也成了 响应式的一个代表函数
而定义它的意义在于 defineProperty不好用

具体不好用在哪呢? 我们打开上文用到的项目
将output.js代码修改如下

const output = () => {
    var obj = {
        a: 11
    };
    
    Object.defineProperty(obj,'a',{
        get() {
            return 31
        },
        set(value) {
            console.log("您正在改变 obj的a属性,修改后的值为",value);
        }
    });
    
    obj.a = 12;
    console.log(obj.a);
    document.getElementById("text").innerHTML = obj.a;
}

export default output

运行结果如下
vue2数据响应式原理(3) 带你手写一个defineReactive响应式函数并理解其本质-LMLPHP
defineProperty的特性
get会的返回值 为元素最终值 这里 我们赋值时 它先被赋值成了12 然后 当你输出的一瞬间 你获取他的值 触发到了 get 于是 这个get就又把它变回返回的这个 31了

但这个问题也并非误解 我们将output.js代码更改如下

const output = () => {
    var obj = {
        a: 11
    };
    let temp;
    
    Object.defineProperty(obj,'a',{
        get() {
            return temp
        },
        set(value) {
            temp = value;
            console.log("您正在改变 obj的a属性,修改后的值为",value);
        }
    });
    
    obj.a = 12;
    console.log(obj.a);
    document.getElementById("text").innerHTML = obj.a;
}

export default output

我们在他们中间 做了一个周转变量 在set中拿到值 然后 在get中将记录的值返回回去
vue2数据响应式原理(3) 带你手写一个defineReactive响应式函数并理解其本质-LMLPHP
但其实 我们现在这个写法 真的是非常的捞 看着

这个 时候 我们就可以定义一个函数 用闭包来写

我们在src下创建一个类 叫 dataResp.js
参考代码如下

export const defineReactive = function(data,key,val,enumerable,configurable) {
    Object.defineProperty(data,key,{
        enumerable,
        configurable,
        get() {
            return val
        },
        set(value) {
            if(value == val) {
                return
            }
            val = value;
        }
    });
}

这样 我们就定义了一个功能的数据响应式声明方法
然后回去将output.js代码更改如下

import { defineReactive } from "./dataResp"
const output = () => {
    var obj = {};
    defineReactive(obj,"a",10,true,true);
    
    document.getElementById("text").innerHTML = obj.a;
}

export default output

这里 我们调用了刚刚写在dataResp.js中的defineReactive函数 第一个参数是要给那个对象声明响应式 我们传入了obj 要给那个键 我们输入了a 然后 他的初始值 我们输入了一个10 后面的enumerable和configurable 就给true
运行结果如下
可以看到 obj.a的值确实是10
vue2数据响应式原理(3) 带你手写一个defineReactive响应式函数并理解其本质-LMLPHP
然后 我们尝试修改响应式变量 看看set 和get 会不会触发
dataResp.js代码修改如下

export const defineReactive = function(data,key,val,enumerable,configurable) {
    Object.defineProperty(data,key,{
        enumerable,
        configurable,
        get() {
            console.log(`您正在获取${key}的值`);
            return val
        },
        set(value) {
            console.log(`您正在修改${key}的值`);
            if(value == val) {
                return
            }
            val = value;
        }
    });
}

我们在get和set中设定了输出语句 然后 更改output.js代码如下

import { defineReactive } from "./dataResp"
const output = () => {
    var obj = {};
    defineReactive(obj,"a",10,true,true);
    obj.a = 20;
    document.getElementById("text").innerHTML = obj.a;
}

export default output

这里 我们通过defineReactive声明了obj.a的响应式之后 修改了obj.a
运行结果如下
vue2数据响应式原理(3) 带你手写一个defineReactive响应式函数并理解其本质-LMLPHP
vue2数据响应式原理(3) 带你手写一个defineReactive响应式函数并理解其本质-LMLPHP

很显然 事件都有被监听

其实defineReactive就是提供了一个闭包的环境

04-20 17:39