這篇文章介紹了Reflect的優點及其靜態方法的使用,並通過Proxy實現了一個觀察者模式示例,展示瞭如何利用Reflect簡化和規範對象操作,避免傳統方式的局限。 ...
Reflect的作用
一開始學習Reflect的時候其實覺得很迷惑,感覺通過Reflect操作Proxy對象或者Object對象總有一種多此一舉的感覺。
為什麼要使用Reflect操作對象,而不是直接在Proxy和Object上做操作呢?
原因之一是:Proxy和Object相關的API和操作方式在早期設計得不合理,不規範。但是Proxy和Object又是屬於比較底層的東西,破壞性的改動會影響到非常多的現有代碼。Reflect的提出就是為瞭解決這個問題,提供了一套現代的、規範的API來操作對象。
Reflect的優點可以由下麵幾點體現出來:
-
在對象上定義屬性失敗時:
Object.defineProperty(obj, name, desc)
直接拋出異常,而Reflect.defineProperty(obj, name, desc)
則是返回false
。 -
將部分命令式的
Object
操作規範化為函數行為:name in obj
變為:Reflect.has(obj, name)
;delete obj[name]
變為:Reflect.deleteProperty(obj, name)
;
-
Reflect簡化了一些操作:
// 老寫法 Function.prototype.apply.call(Math.floor, undefined, [1.75]) // 1 // 新寫法 Reflect.apply(Math.floor, undefined, [1.75]) // 1
靜態方法
-
調用函數:Reflect.apply(target, thisArg, args)
-
調用構造函數:Reflect.construct(target, args)
-
讀屬性:Reflect.get(target, name, receiver)
-
寫屬性:Reflect.set(target, name, value, receiver)
-
定義屬性:Reflect.defineProperty(target, name, desc)
-
刪除屬性:Reflect.deleteProperty(target, name)
-
查詢屬性是否存在:Reflect.has(target, name)
-
對象所有屬性:Reflect.ownKeys(target)
等於
Object.getOwnPropertyNames
和Object.getOwnPropertySymbols
。 -
對象是否可擴展:Reflect.isExtensible(target)
-
讓一個對象不可擴展:Reflect.preventExtensions(target)
-
獲取屬性的描述對象:Reflect.getOwnPropertyDescriptor(target, name)
-
獲取對象的原型對象:Reflect.getPrototypeOf(target)
-
設置對象的原型對象:Reflect.setPrototypeOf(target, prototype)
使用Proxy實現觀察者模式
// 創建一個集合來保存觀察者函數
const observers = new Set();
// 函數:添加新的觀察者函數到觀察者集合中
function observe(fn){
observers.add(fn);
}
// 函數:創建一個可觀察的對象
function observable(target){
// 返回一個代理來攔截對目標對象的修改
return new Proxy(target, {
set(target, name, value, receiver){
// 設置目標對象上的屬性
const result = Reflect.set(target, name, value, receiver);
// 通知所有觀察者函數屬性的變化
notify();
return result;
}
});
}
// 函數:通知所有觀察者函數屬性的變化
function notify(){
// 調用觀察者集合中的每一個觀察者函數
observers.forEach(fn => fn());
}
// =================================================================
// 測試部分
// 創建一個包含count屬性的可觀察對象
let state = observable({
count: 1,
});
// 添加一個觀察者函數,每次state的count屬性更新時,都會在控制台輸出日誌
observe(() => {
console.log('state update: ', state.count);
});
// 多次遞增state的count屬性
state.count++;
state.count++;
state.count++;
輸出結果:
state update: 2
state update: 3
state update: 4