亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

ES6+ Reflect(二)

1. 前言

上一節我們學習了 Reflect 的使用和一些基本的API,本節我們將繼續學習 Reflect 的一些擴展的API。

2 Reflect 擴展方法

2.1 Reflect.defineProperty()

Reflect.defineProperty() 方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性,基本等同于 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 方法可以根據返回值檢查屬性是否被成功定義,而 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()** 通過指定的參數列表發起對目標 (target) 函數的調用。

語法:

Reflect.apply(target, thisArgument, argumentsList)
  • target:目標函數。
  • thisArgument:target 函數調用時綁定的 this 對象。
  • argumentsList:target 函數調用時傳入的實參列表,該參數應該是一個類數組的對象。

apply 函數我們都知道,它可以讓函數執行并可以改變 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() 的調用時傳參是一樣的。都是用于綁定 this 對象然后執行給定函數,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() 可以接收截取字符串的函數。

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 操作符構造函數相似 ,相當于運行 new target(...args) ,提供了一種新的不使用 new 來調用構造函數的方法。

語法:

Reflect.construct(target, argumentsList[, newTarget])

參數:

  • target:被運行的目標構造函數;
  • argumentsList:類數組,目標構造函數調用時的參數;
  • newTarget:(可選)作為新創建對象的原型對象的 constructor 屬性,默認值為 target 。

下面的兩種實例化的方式是一樣的。

function Foo() {
  console.log(arguments);
}

var obj = new Foo(...args);
var obj = Reflect.construct(Foo, args); 

Reflect.construct() 返回值是以 target 函數為構造函數,如果 newTarget 存在,則為 newTarget 。argumentList 為其初始化參數。

對于有沒有傳遞第三個參數,我們可以這樣理解:target 就是唯一的構造函數,但是如果傳遞了第三個參數,那就表示:我們的實例由兩部分組成,實例上綁定在 this 上的屬性部分由第一個參數的構造函數生成;不是實例上的屬性部分則由第三個參數的構造函數生成。下面我們來看下具體的實例:

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類作為構造函數
let a = Reflect.construct(A, ['David']);
// 使用B類作為構造函數
let b = Reflect.construct(A, ['David'], B);

console.log(a);
console.log(b);
a.getName();
b.getAge();

下圖是上面代碼的打印結果,創建實例 a 時沒有第三個參數,它的原型上的 constructor 指向的是類 A,并且有 getName 方法。創建實例 b 時有第三個參數,打印的結果可以看到實例 b 原型上的 constructor 執行的是類 B,并且有 B 上的 getAge 方法。

3. 小結

本節主要講解了 Reflect 擴展方法的使用