圖文不符鎮版圖 [http://www.scalsys.com/assets/download.php?file=/. ./wallpapers/machine-learning-wallpaper/machine-learning-wallpaper_558215.jpg](http://www.scalsys.com/assets/download.php?file=/../wallpapers/machine-learning-wallpaper/machine-learning-wallpaper_558215.jpg)

# [Javascript] 使用 Proxy 為 Object 代理進行前處理

# 藉由 Proxy, 我們可以為 Object 定義屬於自己的 Object 特性

最近工作上碰到一個很特別的需求。

由於公司的多國語言使用的是 JSON Object 來進行管理,上頭希望直接用 key 就可以當作是英文的多國語句,當有某個英文關鍵字沒有被設定時,希望能夠直接以 Objectkey 當作內容輸出。

例如:

var obj = {
    "a": "a",
    "b": 1,
};
console.log(obj["a"]); // "a"
console.log(obj["b"]); // 1
console.log(obj["no setting key"]) // 正常應該要顯示 undefined,但是希望這邊顯示 "no setting key"

這種違反行為的效果著實讓我傷透腦筋,直到後來發現了 ES6 的 Proxy

Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种 “元编程”(meta programming),即对编程语言进行编程。

Proxy 可以理解成,在目标对象之前架设一层 “拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来 “代理” 某些操作,可以译为 “代理器”。 — ECMAScript 6 入门

利用 Proxy ,我們可以擴增 Object 的功能或特性,做出屬於我們自己的物件特性。

Proxy 的使用格式為

obj = new Proxy(目標物件, handler物件);

所謂的 handler 物件 是用來做為 proxy 攔截 目標物件 而存在。因此我們必須在 handler object 中撰寫我們攔截 目標物件 後要進行的 getter , setter 操作 function 。若 handler 沒有給予任何操作方法,則就跟一般物件無異。

以下給幾個範例:

賦值前的檢查

我們可以利用 proxy 來針對要賦值給予物件之前做檢查,以下面 code 為例:

setter 會接收三個參數 target Object , property , value

  • target object : 要被賦值的目標物件。
  • property : 要被賦值的物件屬性 (也就是 key )
  • value : 要賦予的值
let person = new Proxy({}, {
    set: (targetObj, prop, value) => {
    if (prop === 'age') {
        // 如果 要給值的 key 是 'age' 就事先檢查給予的值
        if (!Number.isInteger(value)) {
            // 如果不是 integer 的話,就拋出 Error
            throw new TypeError('The age is not an integer');
        }
        if (value > 200) {
          // 如果 年紀大於 200 的話,也不合理
          throw new RangeError('The age seems invalid');
        }
    }
    // 如果一切正常,則正常給值
    targetObj[prop] = value;
    // 回傳 ok
    return true;
  }
});

上面的這段的結果,會讓 person 變為一個 Proxy 物件,並且在給值前進行檢查,如果給值的對象是 age , 則給的值 必須是不大於 200 的整數 ,否則會賦值失敗。

來看看結果

當我們輸入字串時,會拋出 The age is not an integer 的 error。

當我們輸入浮點數時一樣會拋出 The age is not an integer 的 error。

當我們給予超過 200 的整數時,也會被阻擋掉。

只有當我們給予正確範圍的整數時,才能成功賦值。

而當我們要對物件的 key 賦值時,並不會遭到阻擋。

我們將 person 印出來看看,發現其實是一個 Proxy 物件。

# 因此回到我們今天的主題

上頭希望直接用 key 就可以當作是英文的多國語句,當有某個英文關鍵字沒有被設定時,希望能夠直接以 Objectkey 當作內容輸出。

這該怎麼做呢?

依照 proxy 的思路,就很簡單了。

我們只要在取值時做檢查就可以了。

寫一個 getter function

var language = {
    "I have a pen": "我有一支筆",
    "I have an apple": "我有一顆蘋果",
}
language = new Proxy(language, {
    get: (tar, prop, reveiver) => {
        return ( !tar[prop] ) ? prop : tar[prop]
	}
})

上面的 code 在做的事情就是,當 language 在取值前先進行檢查,若有值則直接回傳原值;否則回傳 key 值。

如此就達到了我們原本的目的了。

來看看結果

# 至此,終於完成了這微小而艱巨的任務啦!

Like z20240z's work