Vue2.x
に基づいてObject.defineProperty
聞くことができません:達成するために存在する多くの制限の追加と削除属性、配列のインデックスと変化する長さ、およびサポートすることができMap
、Set
、WeakMap
とWeakSet
!
プロキシとは何ですか?
MDNは、 -そうで説明されているProxy
(例えば、不動産検索、評価、列挙、関数呼び出しなど)の基本的な動作を定義するカスタム動作オブジェクト。
ターゲット・オブジェクトの操作は、傍受を提供する前に実際には、外の世界に濾過し、書き換え、我々は直接オブジェクト自体を操作することはできませんので、いくつかの操作のデフォルト動作を変更するが、プロキシオブジェクトの操作を介して間接的にオブジェクトをすることができます希望を達成するために、操作対象オブジェクト〜
例を見てください:
OBJ = LET {
名:{名: 'HHH' }、
ARR:[ '食べる'、 '飲料'、 '再生' ]
}
// プロキシ乏しい相溶性が13のSETメソッドGET仲介することができる
// のDefinePropertyのみ特定の性質を切片
せハンドラ = {
GET(ターゲット、KEY){ // キーが内部であるobjをOBJ取ることであるtarget属性
はconsole.log( '依存の収集' )
戻りターゲット[キー]
}、
SET(ターゲット、キー、値){
にconsole.log(「トリガ更新」)
ターゲット[キー] = 値
}
}
せプロキシ = 新しい新プロキシ(OBJ、ハンドラ)
// オブジェクトとプロキシ設定の値を介して
proxy.arr
proxy.name =「123」
これは、オブジェクト(上位プロキシ)エージェントの操作にオブジェクトobj、元のオブジェクトを定義します。値を設定するときには、設定された方法を取る時の値は、getメソッドの戻りに対応する値を行く場合は、更新をトリガ。しかし、これは古い言い回しで、新しい文言を反映使用しています。
反映組み込みオブジェクト、新しいAPIの操作対象が設けられている反映し、内部言語に属するメソッドオブジェクト、すなわちオブジェクト・メソッド、オブジェクトを反映内部からオブジェクトを取るために、オブジェクト上に配置されたオブジェクト。エラーがfalseを返した場合
単純に上の例を書き直します
let handler = {
get (target,key) { //target就是obj key就是要取obj里面的哪个属性
console.log('收集依赖')
// return target[key]
//Reflect 反射 这个方法里面包含了很多api
return Reflect.get(target,key)
},
set (target,key,value) {
console.log('触发更新')
// target[key] = value //这种写法设置时如果不成功也不会报错 比如这个对象默认不可配置
Reflect.set(target,key,value)
}
}
let proxy = new Proxy(obj,handler)
//通过代理后的对象取值和设置值
proxy.arr
proxy.name = '123'
但是有一个问题,这个对象是多层对象,之前Object.defineProperty方法是一开始就会对这个多层对象进行递归处理,而Proxy不会。它是懒代理。如果对这个对象里面的值进行代理就取不到值。就像上面我们只对name进行了代理,并没有对name.name进行代理,所以他就取不到这个值,需要代理之后才能取到。
let obj = {
name:{name:'hhh'},
arr: ['吃','喝','玩']
}
//proxy兼容性差 可以代理13种方法 get set
//defineProperty 只对特定 的属性进行拦截
let handler = {
get (target,key) { //target就是obj key就是要取obj里面的哪个属性
console.log('收集依赖')
if(typeof target[key] === 'object' && target[key] !== null){
//递归代理,只有取到对应值的时候才会代理
return new Proxy(target[key],handler)
}
// return target[key]
//Reflect 反射 这个方法里面包含了很多api
return Reflect.get(target,key)
},
set (target,key,value) {
console.log('触发更新')
// target[key] = value //这种写法设置时如果不成功也不会报错 比如这个对象默认不可配置
Reflect.set(target,key,value)
}
}
let proxy = new Proxy(obj,handler)
可以看到这次虽然我写了代理name.name,但是没有取到name.name,它并不会真正的代理
这次触发了两次收集依赖。
接下来看看数组的代理过程:
let obj = {
name:{name:'hhh'},
arr: ['吃','喝','玩']
}
//proxy兼容性差 可以代理13种方法 get set
//defineProperty 只对特定 的属性进行拦截
let handler = {
get (target,key) { //target就是obj key就是要取obj里面的哪个属性
console.log('收集依赖')
if(typeof target[key] === 'object' && target[key] !== null){
//递归代理,只有取到对应值的时候才会代理
return new Proxy(target[key],handler)
}
// return target[key]
//Reflect 反射 这个方法里面包含了很多api
return Reflect.get(target,key)
},
set (target,key,value) {
console.log('触发更新')
// target[key] = value //这种写法设置时如果不成功也不会报错 比如这个对象默认不可配置
return Reflect.set(target,key,value)
}
}
let proxy = new Proxy(obj,handler)
//通过代理后的对象取值和设置值
// proxy.name.name = '123' //设置值,取一次,设置一次
proxy.arr.push(456)
这里面它会走两次触发更新的操作,因为第一次需要修改数组的长度,第二次再把元素放进数组里。所以我们需要判断一下它是新增操作还是修改操作
set (target,key,value) {
let oldValue = target[key]
console.log(key, oldValue, value)
if(!oldValue){
console.log('新增属性')
}else if(oldValue !== value){
console.log('修改属性')
}
// target[key] = value //这种写法设置时如果不成功也不会报错 比如这个对象默认不可配置
return Reflect.set(target,key,value)
}
首先拿到它的旧值,如果这个值不存在就是新增,如果存在但不相等就是修改操作
可以看到最后一次判断结果是两个相等,什么也不做
这是一次修改操作。
我们知道,vue2.0是不会监控到之前不存在的属性的,但是proxy可以操作之前不存在的属性的,它会拦截设置操作,如下:
xxx之前并不在obj对象里面,但是依旧可以新增。