前兩天認識到 ref
綁定「物件」、Vue 會將其包裝成一個 Proxy
物件的時候,點了官方文件放的 MDN,發現完全看不懂,想說沒關係~好像可以先無視它~結果很快的發現沒辦法銜接到接下來要學的 reactive
⋯⋯
真的完全 GG(然後小裁判在旁邊緊盯著 👀)
Proxy
你到底是什麼啦齁!
MDN:Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
翻譯蒟蒻:Proxy
是一個代理物件,功能是可以創建一個「對目標物件的代理」,去操作攔截和自定義行為(例如存取屬性、更改值等等)。
Proxy
是用 new
建構出來的,語法為:
new Proxy(target, handler)
target
參數:要拿來使用 Proxy
包裝的「目標物件」。handler
參數:也是一個物件,其中通常會定義「函式」屬性,也就是在操作這個代理的時候,要對目標物件執行的行為。行為:定義代理物件其中的參數(也就是上述說的 target
和 handler
)
const target = 某個物件;
const ref = new Proxy(target, {
get: function(target, property){
return 自定義的資料;
}
});
以上範例做了:
target
變數,傳入 new Proxy
作為 target
參數。handler
參數 為 { get: funciton(target, property){ return 自定義的資料; } }
。ref
。行為:
handler
console.log(ref.target1);
以上範例做了:對 ref
物件存取 target1
屬性,因此執行 handler
中定義的 get
函式,可拿到 target1
return 的自定義資料。
我們以一個例子來看:
const name = {
firstName: "Jami",
lastName: "Guo",
};
console.log(`名字`, name.firstName);
console.log(`全名`, name.firstName + name.lastName);
</script>
這裡定義了 name
物件,而 console.log
反映了我們可能會有這兩件事情想做:
然而~我們可以用 Proxy
物件來包裝這樣的需求!
const name = {
firstName: "Jami",
lastName: "Guo",
};
const ref = new Proxy(name, {
get: function (target, property) {
if (property === "fullName") {
return target.firstName + " " + target.lastName;
}
return target[property];
}
});
console.log(ref.fullName);
console.log(ref.firstName);
上述我們做了什麼事:
target
目標物件const name = {
firstName: "Jami",
lastName: "Guo",
};
handler
操作行為{
get: function (target, property) {
if (property === "fullName") {
return target.firstName + " " + target.lastName;
}
return target[property];
}
}
ref
ref
並存取屬性 fullName
。console.log(ref.fullName);
這將會把 fullName
引數帶入 property
,判斷式中條件成立,所以將會執行 return target.firstName + " " + target.lastName;
,印出的結果會是 Jami Guo
。
ref
並存取屬性 firstName
。console.log(ref.firstName);
這將會把 firstName
引數帶入 property
,判斷式中條件不成立,所以將會執行 return target[property];
,也就是 target[firstName]
,印出的結果會是 Jami
。
瀏覽器上執行結果:
來看個更實際的例子!
我們有個物件中存放了身高、體重,期望在執行時就可以做到印出身高、體重或 BMI。
我們可以這樣寫~
const personData = {
height: '1.65',
weight: 99.9
}
const personProxy = new Proxy(personData, {
get: function (target, property) {
if (property === "bmi") {
return personData.weight / (personData.height ** 2);
}
return target[property]
}
})
console.log('BMI', personProxy.bmi);
console.log('身高', personProxy.height);
console.log('體重', personProxy.weight);
當 property === "bmi"
的時候,就 return 了我們定義的算 BMI 的語法,!==
的時候,就 return target[property]
,用 物件[屬性] 取得需要的值(身高或體重)。
於是我們將會印出:
我們將學習概念回到 Vue 響應式系統⋯⋯
當我們通過 ref
存取一個物件的屬性時,背後其實是運用了 Proxy
的概念,而 Proxy
代理物件,可透過「攔截」機制、配合設置的 handler
物件,自定義對目標物件的行為,更新介面。
明天我們繼續說說 Vue 響應式基礎的另外一個語法 reactive
!
學這裡的時候,看了好多文件都不懂,在想說可能換個方式才會懂了~想聽人講解,所以到 youtube 找資料,是最後看了 彭彭這部影片 才覺得有清楚理解的(老師的頻道是我在一年半前學前端的啟蒙 XDDDD)
也想分享一下之前 Chris 在幫我 code review 的時候他提到的想法:
學習的時候,必須知道:具備什麼條件怎麼會讓自己懂。
可能是:先知道這件事情、再小規模練習、再了解之外的特性、再去組合跟什麼很像,然後可能先放著、某天就會突然懂了之類的。
大學的時候,因為要學想學的東西,當想盡辦法要學起來的時候,就會去研究怎樣才學的起來。
需要練習嗎?哪裡我不懂?這件事是不是用看的學會?經過什麼樣的體會才學得會?所以得想辦法拿到那個體會,學會的感覺才會明顯。
而這件事也是得一直有意識地去做才行~~
謝天謝地,繼續加油耶比
https://github.com/Jamixcs/2024iThome-jamixcs/tree/main/src/components/day13
給你另一個 proxy 的想法
https://dwatow.github.io/2022/11-10-pattern/proxy-in-js/
給你另一個 proxy 的想法
https://dwatow.github.io/2022/11-10-pattern/proxy-in-js/