ES6 Proxy與資料劫持 12

2022-05-06 02:06:07 字數 4065 閱讀 1005

隨著前端界的空前繁榮,各種框架橫空出世,包括各類mvvm框架百家爭鳴,比如anglar、vue、react等等,它們最大的優點就是可以實現資料繫結,再也不需要手動進行dom操作了,它們實現的原理也基本上是髒檢查或資料劫持。我們先以vue框架出發,探索其中資料劫持的奧秘。

vue 2.0的版本所使用的資料劫持,說白了就是通過object.defineproperty()來劫持物件屬性的setter和getter操作,在資料變動時做你想要做的事情,舉個栗子:

var data = 

object.keys(data).foreach(function(key),

set:function()

})});data.name //控制台會列印出 「get」

data.name = 'xiaohong' //控制台會列印出 "監聽到資料發生了變化"

但是有沒有比object.defineproperty更好的實現方式呢?

答案是肯定的有,那就是我們今天的主人公:proxy

1、proxy簡介

proxy這個詞的原意是**,用在這裡表示由它來**某些操作,可以譯為**器。

也可以理解成在目標物件之前設定一層攔截,外界對該物件的訪問,都必須先通過這層攔截,因此提供了一種機制,可以對外界的訪問進行過濾和改寫。

在生活中,**模式的場景是十分常見的,例如我們現在如果有購買海外產品(給女朋友買乙個lv的包包,前提是你要先有個女朋友,^_^)的需求,更多的是去找**中介機構,而不是直接去國外買。此時,**起到的作用就是**的作用。

proxy建構函式能夠讓我們輕鬆的使用**模式:

var proxy = new proxy(target, handler);

proxy建構函式中有兩個引數:

target是用proxy包裝的被**物件(可以是任何型別的物件,包括原生陣列,函式,甚至另乙個**)。

handler是乙個物件,其宣告了**target 的一些操作,其屬性是當執行乙個操作時定義**的行為的函式。

講的通俗點,如何讓**幫你買lv的包包呢?

首先,你需要告訴**你看好了哪款包包,這個款式就是proxy裡的第乙個引數target。

其次就是制定購買策略,例如國外比國內便宜20%,就買2個,便宜40%,就買4個,這個策略就是第二個引數handle。

2、proxy中的處理方法

proxy有13種資料劫持的操作,那是相當的強大:

2.1 get方法

get方法是在你得到某物件屬性值時預處理的方法,接受兩個常用引數

可以**來模擬handle中的get方法,如下

var bao = ;

var proxybao = new proxy(bao, else

}});proxybao.price

//"超出客戶心理價位,不買了"

解釋一下:客戶想買乙個lv的包,心理價位是5000,把購買目標和需求都告訴了**,**詢問了下國外的**,這款lv的包是9999,超出了客戶的心理價位,於是不買了。

2.2 set方法

set方法用來攔截某個屬性的賦值操作,可以接受四個引數

假定person物件有乙個age屬性,該屬性應該是乙個不大於 200 的整數,那麼可以使用proxy保證age的屬性值符合要求。

let validator = 

if (value > 200)

}// 對於滿足條件的 age 屬性以及其他屬性,直接儲存

target[key] = value;

}};let person = new proxy({}, validator);

person.age = 100;

person.age // 100

person.age = 'young' // 報錯 the age is not an integer

person.age = 300 // 報錯 the age seems invalid

上面**中,由於設定了存值函式set,任何不符合要求的age屬性賦值,都會丟擲乙個錯誤,這是資料驗證的一種實現方法。

3、proxy相比object.defineproperty的優勢

3.1 支援陣列

let arr = [1,2,3]

let proxy = new proxy(arr, ,

set (target, key, value, receiver)

})proxy.push(4)

// 能夠列印出很多內容

// get push (尋找 proxy.push 方法)

// get length (獲取當前的 length)

// set 3 4 (設定 proxy[3] = 4)

// set length 4 (設定 proxy.length = 4)

proxy 不需要對陣列的方法進行過載,省去了眾多 hack,減少**量等於減少了維護成本,而且標準的就是最好的。

3.2 針對物件

在資料劫持這個問題上,proxy 可以被認為是 object.defineproperty() 的公升級版。外界對某個物件的訪問,都必須經過這層攔截。因此它是針對 整個物件,而不是 物件的某個屬性,所以也就不需要對 keys 進行遍歷。

let obj = 

let handler = ,

set (target, key, value, receiver)

}let proxy = new proxy(obj, handler)

proxy.name = 'zoe' // set name zoe

proxy.age = 18 // set age 18

3.3 巢狀支援

本質上,proxy 也是不支援巢狀的,這點和 object.defineproperty() 是一樣的。因此也需要通過逐層遍歷來解決。proxy 的寫法是在 get 裡面遞迴呼叫 proxy 並返回,**如下:

let obj = 

}let handler =

return reflect.get(target, key, receiver)

},set (target, key, value, receiver)

}let proxy = new proxy(obj, handler)

// 以下兩句都能夠進入 set

proxy.info.name = 'zoe'

proxy.info.blogs.push('proxy')

4、應用例項

4.1 使用proxy實現表單校驗

let person = 

let handler =

if (key === 'age' && typeof value !== 'number')

return reflect.set(target, key, value, receiver)

}}let boy = new proxy(person, handler)

boy.name = 'xiaohong' // ok

boy.age = '18' // 報錯 使用者年齡必須是數字型別

5、總結

proxy本質上屬於元程式設計非破壞性資料劫持,在原物件的基礎上進行了功能的衍生而又不影響原物件,符合松耦合高內聚的設計理念。

通俗的說proxy在資料外層套了個殼,然後通過這層殼訪問內部的資料,就像下面的圖:

proxy讓js開發者很方便的使用**模式,使函式更加強大,業務邏輯更加清楚。

proxy 不但可以取代 object.defineproperty 並且還擴增了非常多的功能。proxy 技術支援監測陣列的 push 等方法操作,支援物件屬性的動態新增和刪除,極大的簡化了響應化的**量。vue 3.0的也會使用proxy去實現部分核心**。

在業務開發時應該注意proxy使用場景,當物件的功能變得複雜或者我們需要進行一定的訪問限制時,便可以考慮使用**。

es6 Proxy 學習筆記

proxy 可以理解成,在目標物件之前架設一層 攔截 外界對物件的訪問都必須先通過這層攔截,通過這種 操作的機制,可以對外界的訪問進行過濾和修改。let person let obj new proxy person,obj.name lilei obj.age 暫無該值 proxy例項通過prox...

ES6 Proxy的學習與理解

前一段時間在位元組跳動時聊到了proxy。起因是問道vue中資料繫結的實現,回答通過設定setter和getter實現,問這樣有什麼缺點,答在對物件的屬性的監控方面存在瑕疵,例如通過直接設定陣列下標進行賦值,或者對物件直接進行修改,是無法觀察到的,必須使用vue.set新增,或者使用array.pr...

es6 proxy的簡單使用

proxy,顧名思義是 的意思 也就是對乙個操作的 比如當我們對乙個物件要進行操作的時候,我們是這樣寫的 展示出來的效果是這樣的 瀏覽器有點問題,所以在node的環境下執行 在使用了proxy後,我們的會變成這樣 結果如下 流程的大概是這樣,1.當我們用了上面的寫法後 不要問為什麼這麼寫,遵守是唯一...