Summary

Function.prototype.apply()将会调用一个以this和数组形式的arguments为参数的方法,而call()方法则只是在第二个参数形式与之不同而已。

fun.apply(thisArg, [argsArray])
fun.call(thisArg, arg1, arg2, arg3...)

Description

每当要为一个新的对象添加一个方法时,有时不得不为其重写一个方法。而如果利用apply的话,只需要写一次方法,然后在这个新的对象中继承它即可,十分方便。

apply和call方法十分相似,仅仅只是参数不同而已,但证实因为这一点,我们在用apply时不必知道被调用的对象的具体参数,可以只传递arguments,如此一来,被调用的这个对象将负责handle传递的agrumets.

Examples

1.Using apply to chain constructors

我们可以像Java那样,利用apply为一个对象创建构造链。在下面的例子中,我们将创建一个名为construct的全局方法,这个方法可以不必让你传递一个一个的参数,取而代之的则是传递一个参数数组。

Function.prototype.construct = function (aArgs) {
  var oNew = Object.create(this.prototype);
  this.apply(oNew, aArgs);
  return oNew;
};

Example usage:

function MyConstructor() {
  for (var nProp = 0; nProp < arguments.length; nProp++) {
    this['property' + nProp] = arguments[nProp];
  }
}

var myArray = [4, 'Hello world!', false];
var myInstance = MyConstructor.construct(myArray);

console.log(myInstance.property1);                // 'Hello world!'
console.log(myInstance instanceof MyConstructor); // 'true'
console.log(myInstance.constructor);              // 'MyConstructor'

2.Using apply and built-in functions

利用apply调用javascript的内建方法是一种比较聪明的用法,例如下面的例子,利用apply调用系统max方法获取最大值。一般如果你要在一个数组中找到最大或最小值,那将不得不进行loop,即使利用系统自带的max函数,那也得传递有限个参数,十分不便。

/* min/max number in an array */
var numbers = [5, 6, 2, 3, 7];

/* using Math.min/Math.max apply */
var max = Math.max.apply(null, numbers); /* This about equal to Math.max(numbers[0], ...)
                                            or Math.max(5, 6, ...) */
var min = Math.min.apply(null, numbers);

3.Using apply in monkey-patching

apply还是一种很好的扩展内置对象方法的方式。如下面的例子,已有someobject.foo方法, 你可以像黑客那样在其原有的基础上修改它,从而破坏其封装性。

var someobject = new Object();
someobject.foo = function() {
    console.log('This is the originalfoo function.');
};

var originalfoo = someobject.foo;
someobject.foo = function() {
  // Do stuff before calling function
  console.log(arguments);
  // Call the function as it would have been called normally:
  originalfoo.apply(this,arguments);
  // Run stuff after, here.
}