ES6+ Reflect(二)
1. 前言
上一節(jié)我們學(xué)習(xí)了 Reflect 的使用和一些基本的API,本節(jié)我們將繼續(xù)學(xué)習(xí) Reflect 的一些擴(kuò)展的API。
2 Reflect 擴(kuò)展方法
2.1 Reflect.defineProperty()
Reflect.defineProperty()
方法會(huì)直接在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)對(duì)象的現(xiàn)有屬性,基本等同于 Object.defineProperty()
方法,唯一不同是 Object.defineProperty()
返回的是這個(gè)對(duì)象,Reflect.defineProperty()
返回的是 Boolean
值。
語法:
Reflect.defineProperty(target, propertyKey, attributes)
- target:目標(biāo)對(duì)象;
- propertyKey:需要定義或修改的屬性的名稱;
- attributes:需要定義或修改的屬性的描述。
如果 target 不是 Object
,拋出一個(gè) TypeError
。
let obj = {}
Reflect.defineProperty(obj, 'a', {value: 10}) // true
obj.a; // 10
Reflect.defineProperty
方法可以根據(jù)返回值檢查屬性是否被成功定義,而 Object.defineProperty
只能通過 try...catch
去捕獲其中的錯(cuò)誤,相比之下 Reflect.defineProperty()
方法更加方便。
var obj = {}
var r = Reflect.defineProperty(obj, 'a', {value: 10})
if (r) {
// 成功 todo
} else {
// 失敗 todo
}
try {
let obj = {}
Object.defineProperty(obj, 'a', {value: 10})
} catch(e) {
// 如果失敗,捕獲的異常
}
2.2 Reflect.apply()
**Reflect.apply()
** 通過指定的參數(shù)列表發(fā)起對(duì)目標(biāo) (target) 函數(shù)的調(diào)用。
語法:
Reflect.apply(target, thisArgument, argumentsList)
- target:目標(biāo)函數(shù)。
- thisArgument:target 函數(shù)調(diào)用時(shí)綁定的 this 對(duì)象。
- argumentsList:target 函數(shù)調(diào)用時(shí)傳入的實(shí)參列表,該參數(shù)應(yīng)該是一個(gè)類數(shù)組的對(duì)象。
apply
函數(shù)我們都知道,它可以讓函數(shù)執(zhí)行并可以改變 this
指向。
const arr = [1, 6, 7, 10, 2, 5];
let max;
max = Math.max.apply(null, arr);
console.log(max); // 10
Reflect.apply()
方法與
上面的代碼中 fn.apply(obj, args)
的寫法還可以寫成 Function.prototype.apply.call(func, thisArg, args)
,Function.prototype.apply.call(fn, obj, args)
這和 Reflect.apply()
的調(diào)用時(shí)傳參是一樣的。都是用于綁定 this
對(duì)象然后執(zhí)行給定函數(shù),Reflect
對(duì)象則簡化這種操作。
max = Function.prototype.apply.call(Math.max, null, arr);
console.log(max); // 10
max = Reflect.apply(Math.max, null, arr);
console.log(max); // 10
Reflect.apply()
可以接收截取字符串的函數(shù)。
let str = 'imooc ES6 wiki';
let newStr;
newStr = Reflect.apply(String.prototype.slice, str, [6, 9]);
console.log(newStr); // ES6
newStr = str.slice(6, 9);
console.log(newStr); // ES6
newStr = String.prototype.slice.apply(str, [6, 9]);
console.log(newStr); // ES6
2.3 Reflect.construct(target, args)
Reflect.construct()
和 new
操作符構(gòu)造函數(shù)相似 ,相當(dāng)于運(yùn)行 new target(...args)
,提供了一種新的不使用 new 來調(diào)用構(gòu)造函數(shù)的方法。
語法:
Reflect.construct(target, argumentsList[, newTarget])
參數(shù):
- target:被運(yùn)行的目標(biāo)構(gòu)造函數(shù);
- argumentsList:類數(shù)組,目標(biāo)構(gòu)造函數(shù)調(diào)用時(shí)的參數(shù);
- newTarget:(可選)作為新創(chuàng)建對(duì)象的原型對(duì)象的
constructor
屬性,默認(rèn)值為target
。
下面的兩種實(shí)例化的方式是一樣的。
function Foo() {
console.log(arguments);
}
var obj = new Foo(...args);
var obj = Reflect.construct(Foo, args);
Reflect.construct()
返回值是以 target
函數(shù)為構(gòu)造函數(shù),如果 newTarget
存在,則為 newTarget
。argumentList
為其初始化參數(shù)。
對(duì)于有沒有傳遞第三個(gè)參數(shù),我們可以這樣理解:target 就是唯一的構(gòu)造函數(shù),但是如果傳遞了第三個(gè)參數(shù),那就表示:我們的實(shí)例由兩部分組成,實(shí)例上綁定在 this 上的屬性部分由第一個(gè)參數(shù)的構(gòu)造函數(shù)生成;不是實(shí)例上的屬性部分則由第三個(gè)參數(shù)的構(gòu)造函數(shù)生成。下面我們來看下具體的實(shí)例:
class A {
constructor(name) {
console.log('init A class');
this.name = name || 'Jack';
}
getName() {
console.log(this.name);
return this.name;
}
}
class B {
constructor(age) {
console.log('init A class');
this.age = age || 18;
}
getAge() {
console.log(this.age);
return this.age;
}
}
// 使用A類作為構(gòu)造函數(shù)
let a = Reflect.construct(A, ['David']);
// 使用B類作為構(gòu)造函數(shù)
let b = Reflect.construct(A, ['David'], B);
console.log(a);
console.log(b);
a.getName();
b.getAge();
下圖是上面代碼的打印結(jié)果,創(chuàng)建實(shí)例 a 時(shí)沒有第三個(gè)參數(shù),它的原型上的 constructor
指向的是類 A,并且有 getName
方法。創(chuàng)建實(shí)例 b 時(shí)有第三個(gè)參數(shù),打印的結(jié)果可以看到實(shí)例 b 原型上的 constructor
執(zhí)行的是類 B,并且有 B 上的 getAge
方法。
3. 小結(jié)
本節(jié)主要講解了 Reflect 擴(kuò)展方法的使用