自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Vue.js設計與實現-Proxy和Reflect

開發(fā) 前端
我們可以看到打印的receiver并不等于state對象。這是因為get方法的第三個參數receiver,可以傳遞對象get調用者指向,即可以正確傳遞上下文。

1.寫在前面

我們知道Vue2的響應式是使用Object.defineProperty來實現的,在實現對象響應式數據比較友好,但是對于實現數組的響應式數據就存在一些問題。而Vue.js3中的對象數據的響應式實現是通過Proxy對原始對象的代理,這樣就能夠在進行取值和設值操作時進行攔截,并對對象數據進行重新定義。那么Proxy是如何實現代理的呢?

2.Proxy代理

Proxy代理就是通過Proxy對一個原始對象進行基本操作的攔截和自定義(如屬性查找、賦值、枚舉、函數調用等)。

const p = new Proxy(target, handler);

在上面代碼片段中,Proxy可以接收兩個參數target、handler:

  • target:表示要進行代理的原始對象(可以是任意類型對象,函數、數組等)。
  • handler:通常以函數作為屬性的對象,該對象是一組夾子(trap),各屬性中的函數分別定義了在執(zhí)行各種操作時代理 p 的行為。

那么接下來,我們就來使用下吧。

const data = {
name:"pingping",
age:18
}

const state = new Proxy(data, {
//攔截屬性取值操作
get(target, key){
//在這里攔截打印數據
console.log(`我的${key}是:${target[key]}`);
return target[key];
},
//攔截屬性設置操作
set(target, key, value){
//在這里攔截設置數據
target[key] = value;
console.log(`我的${key}數據更改為${target[key]}`);
return value
}
});

state.name;

state.name = "onechuan"

打印數據為:

控制臺打印數據

在上面代碼中,我們只用到了get的前兩個參數target和target,分別表示代理的原始對象、被獲取的屬性名。其實Proxy的get方法中還可以傳入第三個參數receiver,表示Proxy代理之后的對象或繼承Proxy的對象。

  • target:被代理的原始對象。
  • property:被獲取的屬性名。
  • receiver:Proxy代理后的對象或者繼承Proxy的對象。
const p = new Proxy(target, {
get: function(target, property, receiver) {
}
});

我們進行個簡單的實踐:

const data = {
name:"pingping",
age:18
}

const state = new Proxy(data, {
get: function(target, property, receiver) {
console.log(state === receiver);
return target[property];
}
});

state.name;

此時,看到控制臺打印的結果是:

控制臺打印結果

在上面舉的例子中,的確receiver指的是Proxy代理之后的對象state,當然receiver也可以指向的是繼承Proxy的對象。

const data = {
name:"pingping",
age:18
}

const state = new Proxy(data, {
get: function(target, property, receiver) {
console.log(state === receiver);
return target[property];
}
});

const obj = {
name:"onechuan"
}

//將obj對象原型設置為state對象,即obj繼承state
Object.setPrototypeOf(obj, state);

obj.name;

控制臺打印結果:

設置繼承的打印結果

在上述代碼和打印結果中,我們可以看到打印的receiver并不等于state對象。這是因為get方法的第三個參數receiver,可以傳遞對象get調用者指向,即可以正確傳遞上下文。

receiver不僅表示Proxy代理后的對象state本身,也會表示繼承Proxy的對象。

const data = {
name:"pingping",
age:18,
get value(){
return this.name;
}
}

const state = new Proxy(data, {
get: function(target, property, receiver) {
console.log(this === receiver);//false
console.log(state === receiver);//false
console.log(obj === receiver);//true
return target[property];
}
});

const obj = {
name:"onechuan"
}

//將obj對象原型設置為state對象,即obj繼承state
Object.setPrototypeOf(obj, state);

obj.value;

我們看到控制臺的打印結果如下:

控制臺打印結果

我們分析下上面代碼,在訪問obj.value時,在obj對象上本身是沒有value屬性的,它會通過原型去查找proxy對象state上的value屬性取值器,會去觸發(fā)state對象上的get value()操作符。此時,會觸發(fā)state對象的取值攔截器,返回target[property]的值,這樣使用obj.value取值就變成了data.value,最終返回的結果就是pingping。

具體的Proxy的一些API見MDN文檔吧。

3.Reflect反射

在了解了Proxy后,我們再來討論下Proxy的好兄弟Reflect,它們是如何配合工作的。

Reflect是一個全局內置的對象,它提供攔截JavaScript操作的方法。但是,Reflect本身不是個函數對象,因此其不是一個構造函數,不能使用new進行調用。Reflect的所有屬性和方法都是靜態(tài)的。

Reflect.get(target, propertyKey[, receiver])
  • target:需要取值的目標對象
  • propertyKey:需要獲取的值的鍵值
  • receiver:如果target對象中指定了getter,receiver則為getter調用時的this值

那么,我們就使用Reflect來獲取對象的屬性吧:

const state = new Proxy(data, {
get: function(target, property, receiver) {
console.log(this === receiver);//false
console.log(state === receiver);//false
console.log(obj === receiver);//true
return Reflect.get(target, property);
// 等價于return target[property];
}
});

在控制臺可以看到,打印結果是一樣的:

控制臺打印結果

在這里,使用Reflect.get(target, property)是等價于return target[property]的,this在Proxy.get攔截器中將this的指向了原始數據data對象,這樣obj.value打印結果自然也是pingping。

如果我們要獲取obj對象自身的name屬性,應該怎么辦?

onst state = new Proxy(data, {
get: function(target, property, receiver) {
console.log(this === receiver);//false
console.log(state === receiver);//false
console.log(obj === receiver);//true
return Reflect.get(target, property, receiver);
// 等價于return target[property];
}
});

打印結果:

打印結果

我們將Proxy.get的第三個參數receiver傳入Reflect.get中,此時我們發(fā)現打印結果就變成了onechuan。這是因為Proxy.get的第三個參數receiver,可以表示代理對象state還可以表示繼承代理對象state的對象obj。而在Reflect.get中傳入了Proxy.get的第三個參數receiver,即obj對象作為參數,此時Reflect.get會把this的指向改為obj。

Reflect.get(target, key, receiver)其實可以理解為target[key].call(receiver),而Reflect.get的參數receiver作用:修改屬性訪問時this的指向receiver。

4.參考文章

《為什么Proxy一定要配合Reflect使用?》

《MDN文檔關于Proxy的描述》

《MDN文檔關于Reflect的描述》

《了解學習 Proxy 的好朋友 - Reflect,為什么需要 Reflect》

5.寫在最后

在Vue.js3中使用Proxy來實現響應式數據,具體就是通過Proxy代理原始對象,通過攔截和修改對象的基本操作。在代理過程中,會出現取值器的this指向問題,此時需要使用Reflect的方法第三個參數receiver來解決。

責任編輯:武曉燕 來源: 前端一碼平川
相關推薦

2022-04-04 16:53:56

Vue.js設計框架

2022-04-12 08:08:57

watch函數options封裝

2022-04-25 07:36:21

組件數據函數

2022-04-01 08:08:27

Vue.js框架命令式

2022-05-03 21:18:38

Vue.js組件KeepAlive

2022-04-26 05:55:06

Vue.js異步組件

2022-04-03 15:44:55

Vue.js框架設計設計與實現

2022-04-18 08:09:44

渲染器DOM掛載Vue.js

2022-04-11 08:03:30

Vue.jscomputed計算屬性

2022-04-05 16:44:59

系統(tǒng)Vue.js響應式

2022-04-17 09:18:11

響應式數據Vue.js

2022-04-09 17:53:56

Vue.js分支切換嵌套的effect

2021-11-26 05:59:31

Vue3 插件Vue應用

2017-07-20 11:18:22

Vue.jsMVVMMVC

2022-04-16 13:59:34

Vue.jsJavascript

2019-04-01 19:38:28

Vue.jsJavascript前端

2022-04-19 23:01:54

Vue.jsDOM節(jié)點DOM樹

2022-04-20 09:07:04

Vue.js的事件處理

2018-04-04 10:32:13

前端JavascriptVue.js

2017-07-04 17:55:37

Vue.js插件開發(fā)
點贊
收藏

51CTO技術棧公眾號