[每日一題]面試官問:談談你對ES6的proxy的理解?

關注「松寶寫代碼」,精選好文,每日一題

作者:saucxs | songEagle

一、前言

2020.12.23 日剛立的 flag,每日一題,題目類型不限制,可以是:算法題,面試題,闡述題等等。

本文是「每日一題」第 8 題:[每日一題]面試官問:談談你對ES6的proxy的理解

[圖片上傳失敗...(image-2f9465-1611537864790)]

二、什么是Proxy?

Proxy,代理,是ES6新增的功能,可以理解為代理器(即由它代理某些操作)。

Proxy 對象用于定義或修改某些操作的自定義行為,可以在外界對目標對象進行訪問前,對外界的訪問進行改寫。

1、Proxy定義

var proxy = new Proxy(target, handler)

new Proxy()表示生成一個 Proxy 實例

  • target:目標對象
  • handler:一個對象,其屬性是當執行一個操作時定義代理的行為的函數。

注意:要實現攔截操作,必須是對 Proxy 實例進行操作,而不是針對目標對象 target 進行操作。

2、proxy攔截get和set操作

我們先來看一下proxy攔截get和set操作,示例代碼如下:

let handler = {
    get: function(target, key, receiver) {
        console.log(`getter ${key}!`)
        return Reflect.get(target, key, receiver)
    },
    set: function(target, key, value, receiver) {
        console.log(`setter ${key}=${value}`)
        return Reflect.set(target, key, value, receiver)
    }
}
var obj = new Proxy({}, handler)
obj.a = 1          // setter a=1
obj.b = undefined  // setter b=undefined

console.log(obj.a, obj.b) 
// getter a!
// getter b!
// 1 undefined

console.log('c' in obj, obj.c)  
// getter c!
// false undefined

3、proxy覆蓋組件的原始行為

我們來看一下,示例代碼如下:

let handler = {
    get: function(target, key, receiver) {
        return 1
    },
    set: function (target, key, value, receiver) {
        console.log(`setting ${key}!`);
        return Reflect.set(target, key, value, receiver);
    }
}
var obj = new Proxy({}, handler)
obj.a = 5       // setting 5!
console.log(obj.a);    // 1

由上面代碼看出:Proxy 不僅是攔截了行為,更是用自己定義的行為覆蓋了組件的原始行為。

若handler = {},則代表 Proxy 沒有做任何攔截,訪問 Proxy 實例就相當于訪問 target 目標對象。

三、Proxy handle方法

  • 1、get(target, key, receiver):攔截 target 屬性的讀取
  • 2、set(target, key, value, receiver):攔截 target 屬性的設置
  • 3、has(target, key):攔截 key in proxy 的操作,并返回是否存在(boolean值)
  • 4、deleteProperty(target, key):攔截 delete proxy[key]的操作,并返回結果(boolean值)
  • 5、ownKeys(target):攔截Object.getOwnPropertyName(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for ... in循環。并返回目標對象所有自身屬性的屬性名數組。注意:Object.keys()的返回結果數組中只包含目標對象自身的可遍歷屬性
  • 6、getOwnPropertyDescriptor(target, key):攔截 Object.getOwnPropertyDescriptor(proxy, key),返回屬性的描述對象
  • 7、defineProperty(target, key, desc):攔截Object.defineProperty(proxy, key, desc)、Object.defineProperties(proxy, descs),返回一個 boolean 值
  • 8、preventExtensions(target):攔截Object.preventExtensions(proxy),返回一個 boolean 值
  • 9、getPrototypeOf(target):攔截Object.getPrototypeOf(proxy),返回一個對象
  • 10、isExtensible(target):攔截Object.isExtensible(proxy),返回一個 boolean 值
  • 11、setPrototypeOf(target, key):攔截Object.setPrototypeOf(proxy, key),返回一個 boolean 值。如果目標對象是函數,則還有兩種額外操作可以被攔截
  • 12、apply(target, object, args):攔截 Proxy 實例作為函數調用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)
  • 13、construct(target, args):攔截 Proxy 實例作為構造函數調用的操作,比如new proxy(...args)

總共 13 個攔截方法,下面進行簡要舉例說明,更多可見阮一峰老師的 《ECMAScript 6 入門》(https://es6.ruanyifeng.com/#docs/proxy

1、get方法和set方法

get方法用于攔截某個屬性的讀取操作,可以接受三個參數,依次為目標對象、屬性名和 proxy 實例本身(嚴格地說,是操作行為所針對的對象),其中最后一個參數可選。

set攔截 target 屬性的設置,可以接受四個參數,依次為目標對象、屬性名、value和 proxy 實例本身(嚴格地說,是操作行為所針對的對象),其中最后一個參數可選。

let target = {foo: 1}
let proxy = new Proxy(target, {
    get(target, key, receiver) {
        console.log(`getter ${key}!`)
        return target[key]
    },
    set: function(target, key, value, receiver) {
        console.log(`setter ${key}!`)
        target[key] = value;
    }
})

let obj = Object.create(proxy)
console.log(obj.foo) 
// getter foo!
// 1

2、has方法

攔截 propKey in proxy 的操作,返回一個布爾值。

// 使用 has 方法隱藏某些屬性,不被 in 運算符發現
var handler = {
    has (target, key) {
        if (key.startsWith('_')) {
            return false;
        }
        return key in target;
    }
};
var foo = { _name: 'saucxs', name: 'saucxs' };
var proxy = new Proxy(foo, handler);
console.log('_name' in proxy); // false
console.log('name' in proxy); // true

3、ownKeys方法

攔截自身屬性的讀取操作。并返回目標對象所有自身屬性的屬性名數組。具體返回結果可結合 MDN 屬性的可枚舉性和所有權

  • Object.getOwnPropertyName(proxy)
  • Object.getOwnPropertySymbols(proxy)
  • Object.keys(proxy)
  • for ... in循環
let target = {
  _foo: 'foo',
  _bar: 'bar',
  name: 'saucxs'
};

let handler = {
  ownKeys (target) {
    return Reflect.ownKeys(target).filter(key => key.startsWith('_'));
  }
};

let proxy = new Proxy(target, handler);
for (let key of Object.keys(proxy)) {
  console.log(target[key]);
}
// "saucxs"

4、apply方法

apply 攔截 Proxy 實例作為函數調用的操作,比如函數的調用(proxy(...args))、call(proxy.call(object, ...args))、apply(proxy.apply(...))等。

var target = function () { return 'I am the target'; };
var handler = {
  apply: function () {
    return 'I am the saucxs proxy';
  }
};

var proxy = new Proxy(target, handler);

proxy();
// "I am the saucxs proxy"

更多可見阮一峰老師的 《ECMAScript 6 入門》(https://es6.ruanyifeng.com/#docs/proxy

往期「每日一題」

1、JavaScript && ES6

2、瀏覽器

3、Vue

4、HTML5

5、算法

6、Node

7、Http

謝謝支持

1、文章喜歡的話可以「分享,點贊,在看」三連哦。

2、作者昵稱:saucxs,songEagle,松寶寫代碼。「松寶寫代碼」作者,每日一題,實驗室等。一個愛好折騰,致力于全棧,正在努力成長的字節跳動工程師,星辰大海,未來可期。內推字節跳動各個部門各個崗位。

3、長按下面圖片,關注「松寶寫代碼」,是獲取開發知識體系構建,精選文章,項目實戰,實驗室,每日一道面試題,進階學習,思考職業發展,涉及到JavaScript,Node,Vue,React,瀏覽器,http,算法,端相關,小程序等領域,希望可以幫助到你,我們一起成長~

[圖片上傳失敗...(image-3fc32c-1611537864790)]

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,533評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,055評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,365評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,561評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,346評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,889評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,978評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,118評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,637評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,558評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,739評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,246評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,980評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,619評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,347評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,702評論 2 370

推薦閱讀更多精彩內容