乐趣区

关于javascript:vue2x版本中ObjectdefineProperty对象属性监听和关联

前言

在 vue2.x 版本官网文档中
深刻响应式原理 https://cn.vuejs.org/v2/guide/reactivity.html 一文的解释当中,Object.defineProperty 将申明响应式 property 数据的状态转换为 getter 和 setter。

Object.defineProperty 根本应用和概念

官网解释的概念是

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

Object.defineProperty() 办法会间接在一个对象上定义一个新属性,或者批改一个对象的现有属性,并返回此对象。

Object.defineProperty(obj, prop, descriptor)

obj: 要在其上定义属性的对象
prop: 要定义或批改的属性的名称或 Symbol
descriptor: 定义或批改的属性的描述符

* @descriptor
*
* configurable    为 true 时,属性能力从新被定义, 默认为 false。* enumerable    为 true 时,该属性才可能呈现在对象的枚举属性中,此时能力通过 for in 遍历属性。默认为 false。* writable    为 true 时,value 属性值能力被批改。默认为 false,此时 value 属性值为只读状态。* value    该属性对应的初始值。能够是任何无效的 JavaScript 值(数值,对象,函数等)。默认为 undefined。* get    一个给属性提供 getter 的办法,如果没有 getter 则为 undefined。当拜访该属性时,该办法会被执行。默认为 undefined。* set    一个给属性提供 setter 的办法,如果没有 setter 则为 undefined。当属性值批改时,触发执行该办法。该办法将承受惟一参数,即该属性新的参数值。默认为 undefined。* 注意事项:get 和 set 它们与 value 和 writable 是互斥的。一旦应用它们,则这个属性就没有保留属性值的能力

Object.defineProperty 新增对象属性

let userInfo = {age: "11",};
console.log("初始 userInfo:", userInfo);
// Object.defineProperty 新增对象属性
Object.defineProperty(userInfo, "name", {
  value: "zhangsan",
  enumerable: true, // 将 enumerable 设为 true 才可能呈现在对象的枚举属性
});
console.log("设置 name 后的 userInfo:", userInfo);
console.log("设置 name 后的 userInfo 属性:", Object.keys(userInfo));

当 enumerable 设置为 false 的时候,咱们通过 Object.keys 枚举属性,并不能获取到 name 属性

应用 Object.defineProperty 批改和监听属性值的变动

let userInfo = {age: "11",};

let initAge = null;
Object.defineProperty(userInfo, "age", {
  enumerable: true,
  configurable: true,
  get: function () {console.log("get 属性办法, 以后对象:", this);
    return initAge;
  },
  set: function (newValue) {console.log("set 属性办法", newValue);
    initAge = newValue;
  },
});
userInfo.age = "30";
console.log("最初 userInfo", userInfo);

通过 get 和 set 操作对象属性相似于咱们在 vue 开发过程中的计算属性 computed 详解,通过 get 和 set 对以后对象进行设置属性值

Object.defineProperty 小结

  • 由下面的的例子咱们能够晓得,当咱们应用 Object.defineProperty 操作对象的时候,都是间接通过对象属性进行操作,而不是对整个对象进行批改,删除和新增,查问属性
  • 在应用 Object.defineProperty 办法操作的时候,一些默认的属性选项,须要咱们留神

Object.defineProperty 和 vue2.x 的分割

回到结尾提到的官网文档中形容的,响应式原理中,如下图

图片源自 vue 官网文档深刻响应式原理:https://cn.vuejs.org/v2/guide/reactivity.html

当组件渲染时,通过对象劫持,遍历 data 状态,那么须要思考的点是:

如果在组件运行时,咱们须要额定增加状态的时候,增加一个新的状态,或者在原有的状态下,增加一个新的属性会产生什么,这个新的状态并不在组件劫持的状态之内:

<p>
  <span style="cursor: pointer; color: red" @click="handleUser"
    > 点击批改不在 data 状态下的值 </span
  >
</p>
<p> 用户信息: name {{defaultUser.name}}, age: {{defaultUser.age}}</p>



data() {
    return {
      defaultUser: {name: "张三",},
    };
  },
  
methods: {handleUser() {
      this.defaultUser.age = "23";
      console.log("数据曾经产生更改,然而视图没有产生更新", this.defaultUser);
    },
  },
  

当咱们点击按钮的时候,视图中的 ui 并没有产生更改,依据官网的文档,咱们能够应用 $set 针对新增的状态进行批改

<p>
      <span style="cursor: pointer; color: red" @click="handleSet"
        > 点击 $set 批改属性值 </span
      >
    </p>
<p> 通过 $set 批改的值:{{setData.name}}</p>


data() {
    return {setData: {},
    };
  },

methods: {handleSet() {this.$set(this.setData, "name", "张三");
    },
  },

除了后续新增的状态无奈进行批改之外,应用 Object.defineProperty 劫持的数据,对数组自身能够操作的到,然而会存在肯定的性能问题,具体不做具体解释,能够参考以下博文,感激该博主的博文,vue 的框架的作者尤大也做了解释:

记一次思否问答的问题思考:Vue 为什么不能检测数组变动 https://segmentfault.com/a/1190000015783546

结语

依据以上例子联合 vue 响应式原理,咱们能够晓得在 vue2.x 版本中 Object.defineProperty 存在以下问题:

1. 监听数组变动下存在性能问题
2.Object.defineProperty 只能劫持对象的属性,并且针对新增的 data 状态,无奈劫持到,只能通过 vue 的扩大办法 $set 进行解决

扩大 vue3 应用的 proxy

阮一峰 -ECMAScript 6 入门
查看最简略的例子和应用办法

下文截取自:阮一峰 -ECMAScript 6 入门 —-> Proxy 能够了解成,在指标对象之前架设一层“拦挡”,外界对该对象的拜访,都必须先通过这层拦挡,因而提供了一种机制,能够对外界的拜访进行过滤和改写。Proxy 这个词的原意是代理,用在这里示意由它来“代理”某些操作,能够译为“代理器”

var obj = new Proxy({}, {get: function (target, propKey, receiver) {console.log(`getting ${propKey}!`);
    return Reflect.get(target, propKey, receiver);
  },
  set: function (target, propKey, value, receiver) {console.log(`setting ${propKey}!`);
    return Reflect.set(target, propKey, value, receiver);
  }
});

Object.defineProperty 比照 Proxy 集体了解

  • Proxy 是针对整个对象的变动进行检测和拦挡,能够晓得对象的属性是新增,删除,还是批改等,都能够通过通过 get 和 set 进行监听失去
  • Object.defineProperty 只针对对象得属性进行操作,联合 vue2.x, 组件渲染实现,后续新增得属性,没方法劫持到
  • Object.defineProperty 针对属性,Proxy 针对整个对象得操作

更多 Object.defineProperty 和 Proxy 的比照,以及 vue3 如果应用 proxy 实现对象的监听,感兴趣的同学能够去搜寻相干博文,后续有工夫再整顿。

源码地址

  • 码云 https://gitee.com/lewyon/vue-note
  • githup https://github.com/akari16/vue-note

文章集体博客地址:vue2.x 版本中 Object.defineProperty 对象属性监听和关联

欢送关注公众号:程序猿布欧,不定期更新一些前端入门文章

创作不易,转载请注明出处和作者。

退出移动版