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进行一个修改。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值