Proxy
概述
Proxy
可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy
这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
而Object.defineProperty
是使用的数据劫持:直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
在访问或者修改对象的某个属性时,通过一段代码拦截这个行为,进行额外的操作或者修改返回结果。数据劫持最典型的应用 -----> 双向的数据绑定(一个常用的面试题),
Vue 2.x
利用Object.defineProperty()
,并且把内部解耦为Observer
,Dep
, 并使用Watcher
相连Vue
在3.x
版本之后改用Proxy
进行实现
Proxy
与Object.defineProperty
的对比
-
Object.defineProperty
- 只能监听对象(
Object
),不能监听数组的变化,无法触发push
,pop
,shift
,unshift
,splice
,sort
,reverse
。 - 必须遍历对象的每个属性
- 只能劫持当前对象属性,如果想深度劫持,必须深层遍历嵌套的对象
- 只能监听对象(
"use strict" let obj = {}; let value = 1 Object.defineProperty(obj, 'listenA', { writable: true, //可修改 enumerable: true, // 可枚举 for...in... Object.keys() configurable: true, // 可配置,可删除 get: () => value, set: val => { console.log(`set obj.listenA .. ${val}`); value = val }, }); obj.listenA = 2 //set obj.listenA .. 2 console.log(obj.listenA) // 2
Proxy
- 可以直接监听对象而非属性
- 可以直接监听数组的变化
// 代理整个对象 let proxyObj = new Proxy({}, { get: (target, key, receiver) => { console.log(`getting ${key}!`); return target[key]; }, set: (target, key, value, receiver) => { console.log(target, key, value, receiver); return target[key] = value; }, }); proxyObj.val = 1; // {} val 1 {} proxyObj.val; // getting val! //代理数组 let proxyArr = new Proxy([], { get: (target, key, receiver) => { console.log(`getting ${key}!`); return target[key]; }, set: (target, key, value, receiver) => { console.log(target, key, value, receiver); return (target[key] = value); }, }); proxyArr[0] = 1; // {} val 1 {} console.log(proxyArr[0]); // getting val! // 1 console.log(proxyArr); // [1]