es6学习笔记11--Proxy和Reflect
Proxy概述
Proxy用于修改某些操作的默認(rèn)行為,等同于在語(yǔ)言層面做出修改,所以屬于一種“元編程”(meta programming),即對(duì)編程語(yǔ)言進(jìn)行編程。
Proxy可以理解成,在目標(biāo)對(duì)象之前架設(shè)一層“攔截”,外界對(duì)該對(duì)象的訪問(wèn),都必須先通過(guò)這層攔截,因此提供了一種機(jī)制,可以對(duì)外界的訪問(wèn)進(jìn)行過(guò)濾和改寫。Proxy這個(gè)詞的原意是代理,用在這里表示由它來(lái)“代理”某些操作,可以譯為“代理器”。
ES6原生提供Proxy構(gòu)造函數(shù),用來(lái)生成Proxy實(shí)例。
var proxy = new Proxy(target, handler);Proxy對(duì)象的所有用法,都是上面這種形式,不同的只是handler參數(shù)的寫法。其中,new Proxy()表示生成一個(gè)Proxy實(shí)例,target參數(shù)表示所要攔截的目標(biāo)對(duì)象,handler參數(shù)也是一個(gè)對(duì)象,用來(lái)定制攔截行為。
下面是另一個(gè)攔截讀取屬性行為的例子。
var proxy = new Proxy({}, {get: function(target, property) {return 35;} });proxy.time // 35 proxy.name // 35 proxy.title // 35上面代碼中,作為構(gòu)造函數(shù),Proxy接受兩個(gè)參數(shù)。第一個(gè)參數(shù)是所要代理的目標(biāo)對(duì)象(上例是一個(gè)空對(duì)象),即如果沒(méi)有Proxy的介入,操作原來(lái)要訪問(wèn)的就是這個(gè)對(duì)象;第二個(gè)參數(shù)是一個(gè)配置對(duì)象,對(duì)于每一個(gè)被代理的操作,需要提供一個(gè)對(duì)應(yīng)的處理函數(shù),該函數(shù)將攔截對(duì)應(yīng)的操作。比如,上面代碼中,配置對(duì)象有一個(gè)get方法,用來(lái)攔截對(duì)目標(biāo)對(duì)象屬性的訪問(wèn)請(qǐng)求。get方法的兩個(gè)參數(shù)分別是目標(biāo)對(duì)象和所要訪問(wèn)的屬性??梢钥吹?#xff0c;由于攔截函數(shù)總是返回35,所以訪問(wèn)任何屬性都得到35。
注意,要使得Proxy起作用,必須針對(duì)Proxy實(shí)例(上例是proxy對(duì)象)進(jìn)行操作,而不是針對(duì)目標(biāo)對(duì)象(上例是空對(duì)象)進(jìn)行操作。
如果handler沒(méi)有設(shè)置任何攔截,那就等同于直接通向原對(duì)象。
var target = {}; var handler = {}; var proxy = new Proxy(target, handler); proxy.a = 'b'; target.a // "b"上面代碼中,handler是一個(gè)空對(duì)象,沒(méi)有任何攔截效果,訪問(wèn)handeler就等同于訪問(wèn)target。
同一個(gè)攔截器函數(shù),可以設(shè)置攔截多個(gè)操作。
var handler = {get: function(target, name) {if (name === 'prototype') return Object.prototype;return 'Hello, ' + name;},apply: function(target, thisBinding, args) { return args[0]; },construct: function(target, args) { return args[1]; } };var fproxy = new Proxy(function(x, y) {return x + y; }, handler);fproxy(1,2); // 1 new fproxy(1,2); // 2 fproxy.prototype; // Object.prototype fproxy.foo; // 'Hello, foo'下面是Proxy支持的攔截操作一覽。
對(duì)于可以設(shè)置、但沒(méi)有設(shè)置攔截的操作,則直接落在目標(biāo)對(duì)象上,按照原先的方式產(chǎn)生結(jié)果。
(1)get(target, propKey, receiver)
攔截對(duì)象屬性的讀取,比如proxy.foo和proxy['foo'],返回類型不限。最后一個(gè)參數(shù)receiver可選,當(dāng)target對(duì)象設(shè)置了propKey屬性的get函數(shù)時(shí),receiver對(duì)象會(huì)綁定get函數(shù)的this對(duì)象。
(2)set(target, propKey, value, receiver)
攔截對(duì)象屬性的設(shè)置,比如proxy.foo = v或proxy['foo'] = v,返回一個(gè)布爾值。
(3)has(target, propKey)
攔截propKey in proxy的操作,返回一個(gè)布爾值。
has方法可以隱藏某些屬性,不被in操作符發(fā)現(xiàn)。
(4)deleteProperty(target, propKey)
攔截delete proxy[propKey]的操作,返回一個(gè)布爾值。
(5)enumerate(target)
攔截for (var x in proxy),返回一個(gè)遍歷器。
注意與Proxy對(duì)象的has方法區(qū)分,后者用來(lái)攔截in操作符,對(duì)for...in循環(huán)無(wú)效。
(6)ownKeys(target)
攔截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy),返回一個(gè)數(shù)組。該方法返回對(duì)象所有自身的屬性,而Object.keys()僅返回對(duì)象可遍歷的屬性。
(7)getOwnPropertyDescriptor(target, propKey)
攔截Object.getOwnPropertyDescriptor(proxy, propKey),返回屬性的描述對(duì)象。
(8)defineProperty(target, propKey, propDesc)
攔截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一個(gè)布爾值。
(9)preventExtensions(target)
攔截Object.preventExtensions(proxy),返回一個(gè)布爾值。
(10)getPrototypeOf(target)
攔截Object.getPrototypeOf(proxy),返回一個(gè)對(duì)象。
(11)isExtensible(target)
攔截Object.isExtensible(proxy),返回一個(gè)布爾值。
(12)setPrototypeOf(target, proto)
攔截Object.setPrototypeOf(proxy, proto),返回一個(gè)布爾值。
如果目標(biāo)對(duì)象是函數(shù),那么還有兩種額外操作可以攔截。
(13)apply(target, object, args)
攔截Proxy實(shí)例作為函數(shù)調(diào)用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。
apply方法可以接受三個(gè)參數(shù),分別是目標(biāo)對(duì)象、目標(biāo)對(duì)象的上下文對(duì)象(this)和目標(biāo)對(duì)象的參數(shù)數(shù)組。
(14)construct(target, args, proxy)
攔截Proxy實(shí)例作為構(gòu)造函數(shù)調(diào)用的操作,比如new proxy(...args)。
construct方法用于攔截new命令。
?
Reflect概述
Reflect對(duì)象與Proxy對(duì)象一樣,也是ES6為了操作對(duì)象而提供的新API。Reflect對(duì)象的設(shè)計(jì)目的有這樣幾個(gè)。
(1) 將Object對(duì)象的一些明顯屬于語(yǔ)言內(nèi)部的方法(比如Object.defineProperty),放到Reflect對(duì)象上?,F(xiàn)階段,某些方法同時(shí)在Object和Reflect對(duì)象上部署,未來(lái)的新方法將只部署在Reflect對(duì)象上。
(2) 修改某些Object方法的返回結(jié)果,讓其變得更合理。比如,Object.defineProperty(obj, name, desc)在無(wú)法定義屬性時(shí),會(huì)拋出一個(gè)錯(cuò)誤,而Reflect.defineProperty(obj, name, desc)則會(huì)返回false。
// 老寫法 try {Object.defineProperty(target, property, attributes);// success } catch (e) {// failure }// 新寫法 if (Reflect.defineProperty(target, property, attributes)) {// success } else {// failure }(3) 讓Object操作都變成函數(shù)行為。某些Object操作是命令式,比如name in obj和delete obj[name],而Reflect.has(obj, name)和Reflect.deleteProperty(obj, name)讓它們變成了函數(shù)行為。
// 老寫法 'assign' in Object // true// 新寫法 Reflect.has(Object, 'assign') // true(4)Reflect對(duì)象的方法與Proxy對(duì)象的方法一一對(duì)應(yīng),只要是Proxy對(duì)象的方法,就能在Reflect對(duì)象上找到對(duì)應(yīng)的方法。這就讓Proxy對(duì)象可以方便地調(diào)用對(duì)應(yīng)的Reflect方法,完成默認(rèn)行為,作為修改行為的基礎(chǔ)。也就是說(shuō),不管Proxy怎么修改默認(rèn)行為,你總可以在Reflect上獲取默認(rèn)行為。
Reflect對(duì)象的方法
Reflect對(duì)象的方法清單如下,共14個(gè)。
- 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)
- Reflect.enumerate(target)
- Reflect.isExtensible(target)
- Reflect.preventExtensions(target)
- Reflect.getOwnPropertyDescriptor(target, name)
- Reflect.getPrototypeOf(target)
- Reflect.setPrototypeOf(target, prototype)
上面這些方法的作用,大部分與Object對(duì)象的同名方法的作用都是相同的,而且它與Proxy對(duì)象的方法是一一對(duì)應(yīng)的。下面是對(duì)其中幾個(gè)方法的解釋。
(1)Reflect.get(target, name, receiver)
查找并返回target對(duì)象的name屬性,如果沒(méi)有該屬性,則返回undefined。
(2)Reflect.set(target, name, value, receiver)
設(shè)置target對(duì)象的name屬性等于value。如果name屬性設(shè)置了賦值函數(shù),則賦值函數(shù)的this綁定receiver。
(3)Reflect.has(obj, name)
等同于name in obj。
(4)Reflect.deleteProperty(obj, name)
等同于delete obj[name]。
(5)Reflect.construct(target, args)
等同于new target(...args),這提供了一種不使用new,來(lái)調(diào)用構(gòu)造函數(shù)的方法。
(6)Reflect.getPrototypeOf(obj)
讀取對(duì)象的__proto__屬性,對(duì)應(yīng)Object.getPrototypeOf(obj)。
(7)Reflect.setPrototypeOf(obj, newProto)
設(shè)置對(duì)象的__proto__屬性,對(duì)應(yīng)Object.setPrototypeOf(obj, newProto)。
(8)Reflect.apply(fun,thisArg,args)
等同于Function.prototype.apply.call(fun,thisArg,args)。一般來(lái)說(shuō),如果要綁定一個(gè)函數(shù)的this對(duì)象,可以這樣寫fn.apply(obj, args),但是如果函數(shù)定義了自己的apply方法,就只能寫成Function.prototype.apply.call(fn, obj, args),采用Reflect對(duì)象可以簡(jiǎn)化這種操作。
另外,需要注意的是,Reflect.set()、Reflect.defineProperty()、Reflect.freeze()、Reflect.seal()和Reflect.preventExtensions()返回一個(gè)布爾值,表示操作是否成功。它們對(duì)應(yīng)的Object方法,失敗時(shí)都會(huì)拋出錯(cuò)誤。
// 失敗時(shí)拋出錯(cuò)誤 Object.defineProperty(obj, name, desc); // 失敗時(shí)返回false Reflect.defineProperty(obj, name, desc);上面代碼中,Reflect.defineProperty方法的作用與Object.defineProperty是一樣的,都是為對(duì)象定義一個(gè)屬性。但是,Reflect.defineProperty方法失敗時(shí),不會(huì)拋出錯(cuò)誤,只會(huì)返回false。
?
?
總結(jié)
以上是生活随笔為你收集整理的es6学习笔记11--Proxy和Reflect的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: zabbix3.0安装过程记录
- 下一篇: python基础之python中if _