vue学习路线(7.数据代理)

115 阅读4分钟

Object.defineProperty() 是Vue中比较底层的一个方法,在数据劫持,数据代理以及计算属性等地方都或多或少的有用到,理解数据代理,需要先熟悉Object.defineProperty() 用法。

一.回顾Object.defineProperty用法

Object.defineProperty() 是 JavaScript 中用于定义或修改对象的属性的方法,可以控制属性的特性(如可枚举性、可配置性、可写性等)。

1.Object.defineProperty() 语法:
Object.defineProperty(obj, prop, descriptor)
2.参数说明:
  • obj: 要定义属性的对象。
  • prop: 要定义或修改的属性的名称。
  • descriptor:属性的描述符对象。
3.descriptor 对象包含以下属性
  • value:属性的值,默认为 undefined
  • enumerable:控制属性是否可以被枚举,默认值是false
  • writable:控制属性是否可以被修改,默认值是false
  • configurable:控制属性是否可以被删除,默认值是false
  • get:获取属性值的函数
  • set:设置属性值的函数
4.案例
1)给对象增加属性

需求:给person对象增加age属性,值为18

let person = {
    name: "张三",
    sex: "男",
    // age:18, //直接在对象里面写可以被枚举
};
Object.defineProperty(person,'age',{
  value:18 //属性的值,默认为 undefined
})
console.log(person); //控制台输出的age颜色更浅,表示age不可以被枚举的,即不参与遍历
console.log(Object.keys(person)) //不输出age

image.png

2)修改对象属性的可枚举性、可配置性、可写性

需求:修改person对象的age属性特性

  Object.defineProperty(person,'age',{
        value:18,//属性的值,默认为 undefined
        enumerable: true, //控制属性是否可以被枚举,默认值是false
        writable: true, //控制属性是否可以被修改,默认值是false
        configurable: true, //控制属性是否可以被删除,默认值是false
  })
Object.defineProperty看起来麻烦,但是可以对追加的属性有更多的限制。
3)读取/修改对象的值

需求:给person增加属性age,且age的取值为number的值。

      let number = 18;
      let person = {
        name: "张三",
        sex: "男",
        // age: number, //用这种方法赋值后,number的值改变时,age不会自动变化
      };
      Object.defineProperty(person, "age", {
        //当有人读取person的age属性值时,get函数(getter)就会被调用,且返回值就是age的值
        get() {
          console.log("有人读取person的age属性值");
          return number; //用这种方法赋值后,number的值改变时,age也会自动变化
        },
        //当有人修改person的age属性值时,set函数(setter)就会被调用,且会收到修改的具体值
        set(value) {
          console.log("有人修改age属性,值是" + value);
          //直接 person.age=10; 不会改变person里面age的值,需要同步改变number的值
          number = value;
        },
      });
      console.log(person);
注意:当配置项当中有setter和getter的时候,value和writable配置项都不能存在,否则报错。

当有人读取对象的属性值时,get函数(getter)就会被调用,且返回值就是属性值。

当有人修改对象的属性值时,set函数(setter)就会被调用,且会收到修改的具体值。

image.png

二.何为数据代理?

数据代理:通过一个对象代理对另一个对象中属性的操作(读/写) 一个简单的数据代理案例

      let obj1 = { x: 1 };
      let obj2 = { y: 2 };
      Object.defineProperty(obj2, "x", {
        get() {
          return obj1.x;
        },
        set(value){
          obj1.x=value;
        }
      });

这个案例中obj2代理obj1,通过操作obj2可以读取obj1的属性值,也可以对obj1的属性赋值,这就是数据代理。

三.vue中的数据代理

 <div id="app">
      <h3>年份:{{year}}</h3>
    </div>
    <script type="text/javascript">
      //创建vue实例
      const vm = new Vue({
        data() {
          return {
            year: 2025,
          };
        },
      });
      vm.$mount("#app");
      console.log(vm);
 
    </script>

image.png 在控制台打印vm,发现year有get和set方法,初步猜测vue中有数据代理,需要验证。

如果验证下图成立,则证明有数据代理:

1747905967351.png

1.getter路径:修改data.year,vm.year会跟着变化。证明当读取vm的year值时,实际取的是data中的year值。

image.png 2.setter路径:vm.year发生修改,data.year会跟着变化。证明当修改vm的year值时,实际上修改的是data中的year值。

image.png

总结:

1.vue中的数据代理:

通过vm对象来代理data对象中属性的操作(读/写)

2.vue中数据代理的好处:

更加方便的操作data中的数据,不用再写vm._data.year
3.基本原理

通过Object.defineProperty()把data对象中的所有属性添加到vm上。 为每一个添加到vm上的属性,都指定一个getter/setter。 在getter/setter内部去操作(读/写)data中对应的属性。

如图解释vue中的数据代理:

image.png