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