众所周知, ES6 新增了一个全局、内建、不可构造的 Reflect 对象,并提供了其下一系列可被拦截的操作方法。其中一个便是 Reflect.apply()了。下面探究下它与传统 ES5 的 Function.prototype.apply() 之间有什么异同。

函数签名

MDN 上两者的函数签名分别如下:

Reflect.apply(target, thisArgument, argumentsList)
function.apply(thisArg, [argsArray])

而 TypeScript 定义的函数签名则分别如下:

declare namespace Reflect {     function apply(target: Function, thisArgument: any, argumentsList: ArrayLike<any>): any; }
interface Function {     apply(this: Function, thisArg: any, argArray?: any): any; }

它们都接受一个提供给被调用函数的 this 参数和一个参数数组(或一个类数组对象, array-like object )。

可选参数

可以最直观看到的是, function.apply() 给函数的第二个传参「参数数组」是可选的,当不需要传递参数给被调用的函数时,可以不传或传递 null、 undefined 值。而由于 function.apply() 只有两个参数,所以实践中连第一个参数也可以一起不传,原理上可以在实现中获得 undefined 值。

(function () { console.log('test1') }).apply() // test1 (function () { console.log('test2') }).apply(undefined, []) // test2 (function () { console.log('test3') }).apply(undefined, {}) // test3 (function (text) { console.log(text) }).apply(undefined, ['test4']) // test4

而 Reflect.apply() 则要求所有参数都必传,如果希望不传参数给被调用的函数,则必须填一个空数组或者空的类数组对象(纯 JavaScript 下空对象也可以,若