ES6+ Reflect(二)
1. 前言
上一節(jié)我們學習了 Reflect 的使用和一些基本的API,本節(jié)我們將繼續(xù)學習 Reflect 的一些擴展的API。
2 Reflect 擴展方法
2.1 Reflect.defineProperty()
Reflect.defineProperty()
方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現(xiàn)有屬性,基本等同于 Object.defineProperty()
方法,唯一不同是 Object.defineProperty()
返回的是這個對象,Reflect.defineProperty()
返回的是 Boolean
值。
語法:
Reflect.defineProperty(target, propertyKey, attributes)
- target:目標對象;
- propertyKey:需要定義或修改的屬性的名稱;
- attributes:需要定義或修改的屬性的描述。
如果 target 不是 Object
,拋出一個 TypeError
。
let obj = {}
Reflect.defineProperty(obj, 'a', {value: 10}) // true
obj.a; // 10
Reflect.defineProperty
方法可以根據(jù)返回值檢查屬性是否被成功定義,而 Object.defineProperty
只能通過 try...catch
去捕獲其中的錯誤,相比之下 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ā)起對目標 (target) 函數(shù)的調(diào)用。
語法:
Reflect.apply(target, thisArgument, argumentsList)
- target:目標函數(shù)。
- thisArgument:target 函數(shù)調(diào)用時綁定的 this 對象。
- argumentsList:target 函數(shù)調(diào)用時傳入的實參列表,該參數(shù)應該是一個類數(shù)組的對象。
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)用時傳參是一樣的。都是用于綁定 this
對象然后執(zhí)行給定函數(shù),Reflect
對象則簡化這種操作。
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
操作符構造函數(shù)相似 ,相當于運行 new target(...args)
,提供了一種新的不使用 new 來調(diào)用構造函數(shù)的方法。
語法:
Reflect.construct(target, argumentsList[, newTarget])
參數(shù):
- target:被運行的目標構造函數(shù);
- argumentsList:類數(shù)組,目標構造函數(shù)調(diào)用時的參數(shù);
- newTarget:(可選)作為新創(chuàng)建對象的原型對象的
constructor
屬性,默認值為target
。
下面的兩種實例化的方式是一樣的。
function Foo() {
console.log(arguments);
}
var obj = new Foo(...args);
var obj = Reflect.construct(Foo, args);
Reflect.construct()
返回值是以 target
函數(shù)為構造函數(shù),如果 newTarget
存在,則為 newTarget
。argumentList
為其初始化參數(shù)。
對于有沒有傳遞第三個參數(shù),我們可以這樣理解:target 就是唯一的構造函數(shù),但是如果傳遞了第三個參數(shù),那就表示:我們的實例由兩部分組成,實例上綁定在 this 上的屬性部分由第一個參數(shù)的構造函數(shù)生成;不是實例上的屬性部分則由第三個參數(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類作為構造函數(shù)
let a = Reflect.construct(A, ['David']);
// 使用B類作為構造函數(shù)
let b = Reflect.construct(A, ['David'], B);
console.log(a);
console.log(b);
a.getName();
b.getAge();
下圖是上面代碼的打印結(jié)果,創(chuàng)建實例 a 時沒有第三個參數(shù),它的原型上的 constructor
指向的是類 A,并且有 getName
方法。創(chuàng)建實例 b 時有第三個參數(shù),打印的結(jié)果可以看到實例 b 原型上的 constructor
執(zhí)行的是類 B,并且有 B 上的 getAge
方法。
3. 小結(jié)
本節(jié)主要講解了 Reflect 擴展方法的使用