關注「松寶寫代碼」,精選好文,每日一題
作者: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
第 16 題:【每日一題】面試官問:JS中如何全面進行客戶端檢測?
第 15 題:【每日一題】面試官問:JS類型判斷有哪幾種方法?
第 14 題:【每日一題】面試官問:談談你對JS對象的創建和引申
第 12 題[每日一題]面試官問:JS引擎的執行過程(二)
第 11 題[每日一題]面試官問:JS引擎的執行過程(一)
第 10 題[每日一題]面試官問:詳細說一下JS數據類型
2、瀏覽器
3、Vue
4、HTML5
5、算法
第 31 道[【每日一題】(31題)面試官:你對圖論了解多少?(一)
第 26 道【每日一題】(26題)算法題:最長公共前綴?
6、Node
7、Http
謝謝支持
1、文章喜歡的話可以「分享,點贊,在看」三連哦。
2、作者昵稱:saucxs,songEagle,松寶寫代碼。「松寶寫代碼」作者,每日一題,實驗室等。一個愛好折騰,致力于全棧,正在努力成長的字節跳動工程師,星辰大海,未來可期。內推字節跳動各個部門各個崗位。
3、長按下面圖片,關注「松寶寫代碼」,是獲取開發知識體系構建,精選文章,項目實戰,實驗室,每日一道面試題,進階學習,思考職業發展,涉及到JavaScript,Node,Vue,React,瀏覽器,http,算法,端相關,小程序等領域,希望可以幫助到你,我們一起成長~
[圖片上傳失敗...(image-3fc32c-1611537864790)]