上一篇介紹了Proxy里面的示例里已經(jīng)部分用到了Reflect草雕。Reflect也是ES6為了操作對象而提供的新的API栏饮,用以替代直接調用Object的方法。參照MDN
現(xiàn)在Object的一些方法省店,如Object.defineProperty之類的底層方法直接暴露出來其實不夠貼切√袅荆現(xiàn)在這些方法會同時部署到Object和Reflect上,未來的新方法將會只部署到Reflect上魔慷。即使舊的Object的方法能用只锭,也應該盡量改用Reflect來替換,因為它部分修改了舊方法中一些不合理的地方院尔。例如Object.defineProperty如果無法定義屬性會拋出異常蜻展,而Reflect.defineProperty將其改為出錯返回false:
//舊寫法
try {
Object.defineProperty(target, property, attributes);
...
} catch (e) {
...
}
//新寫法
if (Reflect.defineProperty(target, property, attributes)) {
...
} else {
...
}
而且部分Object方法是命令式的,如in邀摆,delete操作纵顾。Reflect將其改成了Reflect.has,Reflect.deleteProperty函數(shù)調用:
//舊寫法
var mycar = {make: "Honda", model: "Accord", year: 1998};
console.log("make" in mycar); //true
delete mycar.model;
console.log(mycar); //{ make="Honda", year=1998}
//新寫法
var mycar = {make: "Honda", model: "Accord", year: 1998};
console.log(Reflect.has(mycar, 'make')); //true
Reflect.deleteProperty(mycar, 'model');
console.log(mycar); //{ make="Honda", year=1998}
Reflect的方法和上一篇介紹的Proxy的handler的13個方法是一一對應的栋盹,且和Object的同名方法的作用都是相同的施逾。只要是Proxy對象的方法,就能在Reflect對象上找到對應的方法例获。你可以在Proxy的攔截方法里汉额,調用Reflect同名的方法來執(zhí)行默認的動作。例如一個能打印log的Proxy對象:
var loggedObj = new Proxy(obj, {
get(target, name) {
console.log('get', target, name);
return Reflect.get(target, name);
},
deleteProperty(target, name) {
console.log('delete' + name);
return Reflect.deleteProperty(target, name);
},
has(target, name) {
console.log('has' + name);
return Reflect.has(target, name);
}
});
因為在Proxy一文中已經(jīng)詳細介紹了榨汤,因此這里簡要地介紹一下Reflect的這些同名方法蠕搜。
getPrototypeOf / setPrototypeOf
Reflect.getPrototypeOf對應Object.getPrototypeOf(obj) ,用于讀取對象的proto件余。
Reflect.setPrototypeOf對應Object.setPrototypeOf(obj, newProto)讥脐,用于設置對象的proto遭居。
isExtensible / preventExtensions
Reflect.isExtensible對應Object.isExtensible(obj)
Reflect.preventExtensions等同于Object.preventExtensions(obj)
ownKeys / getOwnPropertyDescriptor
Reflect.ownKeys等同于Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))
Reflect.getOwnPropertyDescriptor等同于Object.getOwnPropertyDescriptor(obj, prop)
defineProperty / deleteProperty
Reflect.defineProperty對應Object.defineProperty(obj, prop, descriptor)
Reflect.deleteProperty等同于delete obj[name]
get / set / has
Reflect.get用于獲取對象的name屬性,如果沒有該屬性會返回undefined旬渠。如果name屬性部署了讀取函數(shù)俱萍,則讀取函數(shù)的this綁定receiver。
Reflect.set用于設置對象的name屬性的值告丢。如果name屬性設置了賦值函數(shù)枪蘑,則賦值函數(shù)的this綁定receiver。
Reflect.has等同于name in obj岖免。
apply / construct
Reflect.apply等同于Function.prototype.apply.call(fun,thisArg,args)岳颇。Reflect的寫法相對簡單,例如:
//舊寫法
console.log(Function.prototype.apply.call(Math.floor, undefined, [1.75])); //1
//新寫法
console.log(Reflect.apply(Math.floor, undefined, [1.75])); //1
Reflect.construct等同于new target(…args)颅湘,現(xiàn)在你可以不使用new话侧,就能調用構造函數(shù)。
有關Proxy和Reflect可以閱讀阮一峰的《ECMAScript 6入門》一書闯参。這兩篇內容大量參照了此書瞻鹏。對作者表示感謝。