• Vue数据代理


    1 Object.defineProperty方法

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

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

    在默认情况下,使用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: '橘猫吃不胖' }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    由上面代码可知,无法修改和删除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); // {}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    示例:自定义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); // 张三
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    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;
        }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    以上代码就是最简单的一个数据代理,我们可以通过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
    
    • 1
    • 2
    • 3
    • 4
    • 5

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    我们在控制台输出一下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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

    验证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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述
    这时我们就验证了vm._data就是在Vue配置项中的data。回到我们之前通过vm.name将张三修改为橘猫吃不胖,那么我们可以通过观察vm._data.name是否被修改来验证setter方法,从结果可以看到,答案是正确的。
    在这里插入图片描述
    因此,当我们使用vm.name = "橘猫吃不胖"来将name从张三修改为橘猫吃不胖时,那么就会通过setter方法将data进行一个修改。

  • 相关阅读:
    windows docker 容器启动报错:Ports are not available
    零拷贝技术:减少数据复制和上下文切换,提高网络传输效率(下)
    【Python】PaddleOCR文字识别国产之光 从安装到pycharm中测试 (保姆级图文)
    【三】Spring Cloud Ribbon 实战
    R语言的向量数据循环规则以及自动补齐机制(Recycling Rule)、在函数中也可以使用自动循环补齐机制(以cbind函数为例)
    Java【初识static、代码块、抽象类、接口、内部类】
    Spring Cloud Seata 分布式事务学习总结
    4 个 Linux 技巧让工作效率翻倍
    不下载软件,可以把电脑本地文件快速传到远端服务器里吗?
    论文解读(GATv2)《How Attentive are Graph Attention Networks?》
  • 原文地址:https://blog.csdn.net/m0_46612221/article/details/125449514