回顾以往的书签,原本是打算写一点 Vue 响应式原理相关的一点内容,但是 Vue 官网只是简单的描述了基本原理,并没有详细对整个过程进行阐述(毕竟相关 API MDN 上都可以查得到,也并非所有人都关心程序内部的细节),所以这算是一篇笔记。
Object.defineProperty
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
应当直接在 Object 构造器对象上调用此方法,而不是在任意一个 Object 类型的实例上调用
语法: Object.defineProperty(obj, prop, descriptor)
obj:要定义属性的对象。 prop:要定义或修改的属性的名称或 Symbol 。 descriptor:要定义或修改的属性描述符。 configurable:当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。 enumerable:当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。 value:该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。 writable:当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符改变。 get:属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。 set:属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。
如果一个描述符同时拥有 value 或 writable 和 get 或 set 键,则会产生一个异常
以上只是对 Object.defineProperty 的介绍,今天的重点是自定义 Setters 和 Getters,这也是 Vue3 之前响应式原理的核心。
1 | var obj = {}; |
如果我们在自定义 Setters 中添加回调函数,就可以实现数据驱动界面了,我认为这才是 vue3 之前版本实现响应式原理的核心。
Object.defineProperties
既然都看到 Object.defineProperty, 也顺便看看 Object.defineProperties
Object.defineProperties() 方法直接在一个对象上定义新的属性或修改现有属性,并返回该对象。
语法: Object.defineProperty(obj, props)
看描述和语法,Object.defineProperties 和 Object.defineProperty 只是参入上的差别,区别在一一个属性和多个属性,直接看代码:
1 | var obj = {}; |
Proxy
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
语法: const p = new Proxy(target, handler)
target: 要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。 handler: 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。
1 | let view = new Proxy( |
同理,如果我们在 set 方法内设置对应的回调函数,也实现了响应式更新。
对比
由于 Object.defineProperties 和 Object.defineProperty 基本可以算是相同的 api 的不同写法,此处仅对比 Object.defineProperty 和 Proxy。
监听范围
Object.defineProperty
Object.defineProperty 只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。
Object.defineProperty 不能监听数组。是通过重写数据的那 7 个可以改变数据的方法来对数组进行监听的。
Object.defineProperty 也不能对 es6 新产生的 Map,Set 这些数据结构做出监听。
Object.defineProperty 也不能监听新增和删除操作,通过 Vue.set()和 Vue.delete 来实现响应式的。
Proxy
Proxy 可以直接监听整个对象而非属性。
Proxy 可以直接监听数组的变化。
Proxy 有 13 中拦截方法,如 ownKeys、deleteProperty、has 等是 Object.defineProperty 不具备的。
Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改;
Proxy 做为新标准将受到浏览器产商重点持续的性能优化,也就是传说中的新标准的性能红利。
兼容性
Object.defineProperty
兼容性好,支持 IE9,而 Proxy 的存在浏览器兼容性问题,而且无法用 polyfill 磨平。
Proxy
不支持 IE
[越努力,越幸运!]