Vue数据代理

Posted 橘猫吃不胖~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue数据代理相关的知识,希望对你有一定的参考价值。

Vue数据代理

1 Object.defineProperty方法

在Vue中,有很多地方使用到了Object.defineProperty方法,例如数据劫持、数据代理、计算属性等。Object.defineProperty方法用来给一个对象添加属性,或者修改一个对象上的属性。它的语法如下:

Object.defineProperty(obj, prop, descriptor)
// obj:要定义属性的对象
// prop:要定义或修改的属性名称或Symbol
// descriptor:要定义或修改的属性描述符
// 返回值:该对象

在默认情况下,使用Object.defineProperty添加的属性不可以执行枚举、修改等操作,因此需要在descriptor中添加响应的配置项,配置项具体如下:

配置项描述
value该属性对应的值,可以是任何有效的javascript 值(数值,对象,函数等),默认为undefined
enumerable表示该属性是否可以枚举,true为可枚举,默认为false不可枚举
writable控制属性是否可以被修改,true为可以修改,默认为false
configurable控制属性是否可以被删除,true为可以被删除,默认为false
get()属性的getter函数,当访问该属性时,会调用此函数,该函数的返回值会被用作属性的值
set()属性的setter函数,当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),默认为undefined

示例:使用Object.defineProperty()方法为person对象添加一个新属性

let person = ;
Object.defineProperty(person, "name", 
    value: "橘猫吃不胖", // name属性值为橘猫吃不胖
    enumerable: true, // 属性可以枚举
)
console.log(person) //  name: '橘猫吃不胖' 
person.name = "张三"; // 修改name属性值为张三,结果不能修改
console.log(person) //  name: '橘猫吃不胖' 
delete person.name; // 删除该属性,结果不能删除
console.log(person) //  name: '橘猫吃不胖' 

由上面代码可知,无法修改和删除name属性,因此为其再添加配置项writable(是否可以被修改)和configurable(是否可以被删除),就可以执行修改和删除的操作了,代码如下:

let person = ;
Object.defineProperty(person, "name", 
    value: "橘猫吃不胖", // name属性值为橘猫吃不胖
    enumerable: true, // 属性可以枚举
    writable: true, // 属性可以被修改
    configurable: true, // 属性可以被删除
)
console.log(person); //  name: '橘猫吃不胖' 
person.name = "张三";
console.log(person); //  name: '张三' 
delete person.name;
console.log(person); // 

示例:自定义setter和getter

let person = ;
let str = "橘猫吃不胖";
Object.defineProperty(person, "name", 
    get()  // 返回一个字符串
        return str;
    ,
    set(value) 
        str = value; // 将字符串的值改为最新的值
    
)
console.log(person.name); // 橘猫吃不胖
person.name = "张三";
console.log(person.name); // 张三

2 什么是数据代理

数据代理就是通过一个对象代理对另一个对象中属性的操作(读/写)。

比如说,有两个对象obj1和obj2,其中obj1中有一个属性x,但是在obj2中可以读取和修改obj1中的属性x,这样就达到了一个数据代理的效果,代码如下:

let obj1 =  x: 100 ;
let obj2 =  y: 200 ;
// 通过Object.defineProperty()方法为obj2添加属性x
Object.defineProperty(obj2, "x", 
    get()  // 读取时返回obj1的x值
        return obj1.x;
    ,
    set(value)  // 修改时更改obj1的x值
        obj1.x = value;
    
)

以上代码就是最简单的一个数据代理,我们可以通过obj2访问并修改obj1中的x的值,示例如下:

console.log(obj2.x); // 100
console.log(obj1.x); // 100
obj2.x = 150; // 通过obj2修改x的值为150
console.log(obj2.x); // 150
console.log(obj1.x); // 150

3 Vue中的数据代理

下面一段代码中,我们在data中定义了nameage,然后在页面上使用双大括号进行了数据显示。其中,Vue实例vm的身上会出现nameage两个属性。

    <div id="app">
        <h3>姓名:name</h3>
        <h3>年龄:age</h3>
    </div>
    <script>
        var vm = new Vue(
            el: "#app",
            data: 
                name: "橘猫吃不胖",
                age: "2岁"
            
        )
    </script>

我们在控制台输出一下vm实例,可以看到nameage两个属性,当我们将鼠标悬停在(...)上时,显示了Invoke property getter。通过对Object.defineProperty()方法的了解,我们可以知道nameage两个属性都是通过Object.defineProperty()方法添加上来的。

当访问name时,是getter在工作,当修改name时,是setter在工作,因此,在vm中,我们也可以看到它们的getter和setter方法。

那么我们通过vm读取与修改name都是通过读取与修改data中的name,这就是一个数据代理


接下来可以对我们刚才的结论进行验证。

验证getter方法

验证思路如下:当我们修改data中的name时,vm中的name也会进行一个修改。首先在控制台读取当前的namevm.name,我们通过vm来获得name,那么getter会将data中的name返回给vm

那么接下来我们将data中的name修改为张三,然后再来访问vm中的name,发现这时name变成了张三,此时我们就验证了getter方法。

    <div id="app">
        <h3>姓名:name</h3>
        <h3>年龄:age</h3>
    </div>
    <script>
        var vm = new Vue(
            el: "#app",
            data: 
                name: "张三", // name修改为张三
                age: "2岁"
            
        )
    </script>

验证setter方法

在上面代码中我们将name修改为了张三,那么我们在控制台修改vm.name为橘猫吃不胖,这时会将data中的name修改为橘猫吃不胖。这个变化我们并不能通过我们的代码看出来,也不能通过普通的data.name拿到dataname的值,因此我们需要通过其他的途径拿到data的值。

这时我们发现,Vue实例vm中的_data属性帮我们存储了data的值,下面我们先对这个进行一个简单的验证。

思路如下,在代码中将data在外部定义,通过验证vm._data === options.data === data来验证我们的想法,其中options就是new Vue()中大括号内的配置项,这时options.data就是我们在外部定义的data,具体代码如下:

    <div id="app">
        <h3>姓名:name</h3>
        <h3>年龄:age</h3>
    </div>
    <script>
        let data = 
            name: "张三",
            age: "2岁"
        
        var vm = new Vue(
            el: "#app",
            data
        )
    </script>


这时我们就验证了vm._data就是在Vue配置项中的data。回到我们之前通过vm.name将张三修改为橘猫吃不胖,那么我们可以通过观察vm._data.name是否被修改来验证setter方法,从结果可以看到,答案是正确的。

因此,当我们使用vm.name = "橘猫吃不胖"来将name从张三修改为橘猫吃不胖时,那么就会通过setter方法将data进行一个修改。

以上是关于Vue数据代理的主要内容,如果未能解决你的问题,请参考以下文章

vue 数据劫持

Vue学习——第四弹

聊聊Vue中的数据代理

在 Vue 3 中将数据对象设置为来自 Promise 的值

vue的proxy代理使用

Vue数据代理