簡介:
-
Object.defineProperty() 是 JavaScript 中一個強大且常用的方法,用于定義對象屬性,允許我們精確地控制屬性的行為,包括讀取、寫入和刪除等操作,是vue2中雙向數據綁定的原理;
-
new Proxy() 是ES6中一種用于創建代理對象的特殊對象,它允許我們攔截并自定義目標對象的操作,例如屬性訪問、賦值、函數調用等。Proxy提供了一種機制,可以在目標對象上設置攔截器,從而攔截對目標對象的操作,是vue3中雙向數據綁定的原理。
一、Object.defineProperty()
1、詳細介紹
?Object.defineProperty()方法?是一個用于定義或修改對象屬性的方法,可以精確地控制屬性的行為,例如可寫性、可枚舉性和可配置性;在Object.defineProperty 方法中,有三個必需的參數和一個可選的第四參數。
- obj (必需):要定義屬性的對象。可以是任何 JavaScript 對象。
- prop (必需):要定義或修改的屬性的名稱。可以是一個字符串,表示屬性的名稱。
- descriptor (必需):一個對象,用于定義或修改屬性的特性。
還可以包含以下可選的屬性:
- - configurable (可選):布爾值,表示該屬性是否可以被刪除或修改特性。默認為 false。
- - enumerable (可選):布爾值,表示該屬性是否可以在 for...in 循環中被枚舉。默認為 false。
- - value (可選):任意類型的值,表示屬性的初始值。默認為 undefined。
- - writable (可選):布爾值,表示該屬性的值是否可以被修改。默認為 false。
- - get (可選):函數,表示獲取屬性值時要調用的函數。
- - set (可選):函數,表示設置屬性值時要調用的函數。
2、使用實例
const obj = { name: "小明", age: 18 }//或者const obj = { }//這里不能使用const,const定義的是常量,無法修改;let demoBute= obj.name;//使用 Object.defineProperty 定義屬性名為 name 的屬性Object.defineProperty(obj, "name", {//可枚舉屬性,可以在 for...in 循環中被枚舉enumerable: true,//可配置屬性,可以使用 delete 運算符刪除屬性configurable: true,//獲取屬性值的函數get: function () {console.log("獲取,收集依賴");return demoBute},//設置屬性值的函數set: function (value) {console.log("更新,通知用戶");demoBute = value;}})//修改,觸發set函數obj.name = "小紅"//控制臺輸出:更新,通知用戶//調用,出發get函數console.log(obj.name);//控制臺輸出:獲取,收集依賴//小明//多次調用,看下運行順序,按照調用順序依次執行(set > get > log)//只要調用obj都會觸發依賴函數obj.name = "小紅"; //set >console.log(obj.name); //get > log//控制臺輸出: //更新,通知用戶//獲取,收集依賴//小紅
3、注意事項
-
?get 函數的作用是在訪問屬性值時被調用,它不接受任何參數,但需要返回屬性的值。在示例中,我們通過return demoBute返回了name的屬性值 ;
-
set 函數的作用是在設置屬性值時被調用,它接受一個參數 value,該參數表示要設置的屬性值。在示例中,我們直接把修改后的值value 賦值給demoBute,實現更新;
-
get 和set 函數,不會同時被觸發,它們根據屬性的讀取或設置操作來決定調用哪個函數;
-
該方法按照調用順序,從上到下依次執行,就是有更新就只運行set函數,沒更新,就只運行get函數;
二、new?Proxy()
1、詳細介紹
?new Proxy() 方法是一個允許您攔截并自定義對象的底層操作。通過使用Proxy,您可以攔截對象的各種操作,如屬性訪問、屬性賦值、函數調用等,并在這些操作發生時執行自定義行為;在Proxy中,常用的有兩個參數target和handler,target 是您要代理的目標對象, handler 是一個包含各種攔截操作的對象。 handler 對象中的每個屬性都是一個特殊的攔截器,用于攔截不同的操作。
2、基本語法
const target = {...... }const handler = {get(target, property, receiver){//攔截屬性的讀取操作},set(target, property, value, receiver){//攔截屬性}
}???????const proxy = new Proxy(target, handler);
3、使用實例
在Proxy中,get和set是handler對象中兩個常用的攔截器函數,用于攔截對象屬性的讀取和賦值操作。下面詳細介紹這兩個函數的用法和功能:
(1)、get(target , property , receiver)
- - target :目標對象,即被代理的對象。
- - property :要訪問的屬性名。
- - receiver:最初被調用的對象,通常是代理對象或繼承代理對象的對象。 - 返回值:返回屬性的值。
get 函數在訪問目標對象的屬性時觸發,可以用來攔截屬性的讀取操作。您可以在 get 函數內部添加自定義的邏輯,例如記錄日志、驗證訪問權限等。下面是一個示例:
const target = {name: "Bob",age: 18
};
const handler = {get(target, property, receiver) {console.log(`正在讀取屬性:${property}`);return target[property];}
};
const proxy = new Proxy(target, handler);
console.log(proxy.name); // 輸出:正在讀取屬性:name,Bob
console.log(proxy.age); // 輸出:正在讀取屬性:age,18
這里我們創建了一個代理對象 proxy ,當訪問 proxy 的屬性時, get 函數會被觸發,并打印相應的日志信息。
(2)、set(target , property , value , receiver)?
- - target :目標對象,即被代理的對象。
- - property :要設置的屬性名。
- - value :要設置的屬性值。
- - receiver:最初被調用的對象,通常是代理對象或繼承代理對象的對象。 - 返回值:返回一個布爾值,表示屬性是否設置成功。???????
set 函數在給目標對象的屬性賦值時觸發,可以用來攔截屬性的賦值操作。您可以在 set 函數內部添加自定義的邏輯,例如驗證賦值的合法性、記錄日志等。下面是一個示例:
const target = {name: "Carl",age: 20
};
const handler = {set(target, property, value, receiver) {console.log(`正在設置屬性:${property},新值為:${value}`);target[property] = value;return true;}
};
const proxy = new Proxy(target, handler);
proxy.age = 30; // 輸出:正在設置屬性:age,新值為:30
console.log(proxy.age); // 輸出:30
在這里,我們給proxy的age屬性賦值時,set函數會被觸發,并打印相應的日志信息;通過get 和 set 攔截器函數,您可以在讀取和賦值屬性時執行自定義的行為,從而實現更靈活和可控的對象操作。
(3)、完整實例?????
const target = {name: "Alice",age: 25
};const handler = {get(target, property, receiver) {console.log(`正在讀取屬性:${property}`);return target[property];},set(target, property, value, receiver) {console.log(`正在設置屬性:${property},新值為:${value}`);target[property] = value;return true;}
};const proxy = new Proxy(target, handler);console.log(proxy.name); // 輸出:正在讀取屬性:name,Alice
proxy.age = 30; // 輸出:正在設置屬性:age,新值為:30
console.log(proxy.age); // 輸出:正在讀取屬性:age,30
4、handler對象中的其它參數
- ?get(target, property, receiver):攔截屬性的讀取操作。
- ?set(target, property, value, receiver):攔截屬性的賦值操作。
- ?apply(target, thisArg, argumentsList):攔截函數的調用操作。
- ?has(target, property):攔截in操作符的操作。
- ?deleteProperty(target, property):攔截屬性的刪除操作