Function.prototype.apply()

概述

apply() 方法可以在使用一个指定的 this 值和一个参数数组(或类数组对象)的前提下调用某个函数或方法。

注:该方法的作用和  call()  方法类似,只有一个区别就是, call()方法接受的是若干个参数的列表,而 apply() 方法接受的是一个包含多个参数的数组(或类数组对象)。

语法

fun.apply(thisArg[, argsArray])

参数

thisArg
在  fun 函数运行时指定的  this  值。需要注意的是,指定的  this 值并不一定是该函数执行时真正的  this 值,如果这个函数处于 非严格模式下,则指定为  null 或  undefined 时 会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的  this 会指向该原始值的自动包装对象。
argsArray
一个数组或者类数组对象,其中的数组元素将作为单独的参数传给  fun 函数。如果该参数的值 为null 或  undefined,则表示不需要传入任何参数。

JavaScript 1.8.5 note

从JavaScript 1.8.5 (Firefox 4)开始,根据 ES5 规范,argsArray 参数可以是一个数组或者任意类数组对象,在这之前实现的是 ES3 规范,其中 argsArray 参数只能是数组对象或者是 arguments 对象(也是类数组对象)

查看bug 562448了解这个变化的详情.

描述

在调用一个存在的函数时,你可以为其指定一个 this 对象。 this 指当前对象,也就是正在调用这个函数的对象。 使用 apply, 你可以只写一次这个方法然后在另一个对象中继承它,而不用在新对象中重复写该方法。

apply 与 call() 非常相似,不同在于所提供的参数类型。apply 使用参数数组而不是一组参数列表(原文:a named set of parameters)。使用 apply, 可以使用数组字面量(array literal)形式,例如,fun.apply(this, ['eat', 'bananas']),,或者数组对象形式, 例如, fun.apply(this, new Array('eat', 'bananas'))

你也可以使用 arguments  对象作为 argsArray 参数。 arguments 是一个函数的局部变量。 It can be used for all unspecified arguments of the called object. Thus, you do not have to know the arguments of the called object when you use the apply method. You can use arguments to pass all the arguments to the called object. The called object is then responsible for handling the arguments.

从 ECMAScript 第5版开始,可以使用任何种类的类数组对象,就是说只要有一个 length 属性和[0...length) 范围的整数属性。例如现在可以使用 NodeList 或一个自己定义的类似 {'length': 2, '0': 'eat', '1': 'bananas'} 形式的对象。

Note: Most browsers, including Chrome 14 and Internet Explorer 9, still do not accept array like objects and will throw an exception.

示例

Using apply to chain constructors

You can use apply to chain constructors for an object, similar to Java. In the following example we will create a global Function method called construct, which will make you able to use an array-like object with a constructor instead of an arguments list.

Function.prototype.construct = function (aArgs) {
    var fConstructor = this, fNewConstr = function () { fConstructor.apply(this, aArgs); };
    fNewConstr.prototype = fConstructor.prototype;
    return new fNewConstr();
};
 
 

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);

alert(myInstance.property1); // alerts "Hello world!"
alert(myInstance instanceof MyConstructor); // alerts "true"
alert(myInstance.constructor); // alerts "MyConstructor"
 
 
Note: This non-native  Function.construct method will not work with some native constructors (like  Date, for example). In these cases you have to use the  Function.bind method (for example, imagine to have an array like the following, to be used with  Date constructor:  [2012, 11, 4]; in this case you have to write something like:  new (Function.prototype.bind.apply(Date, [null].concat([2012, 11, 4])))() – anyhow this is not the best way to do things and probably should not be used in any production environment).

apply and built-in functions

Clever usage of apply allows you to use built-ins functions for some tasks that otherwise probably would have been written by looping over the array values. As an example here we are going to use Math.max/Math.min to find out the maximum/minimum value in an array.

/* 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);

/* vs. simple loop based algorithm */
max = -Infinity, min = +Infinity;

for (var i = 0; i < numbers.length; i++) {
  if (numbers[i] > max)
    max = numbers[i];
  if (numbers[i] < min) 
    min = numbers[i];
}
 
 

但是当心: 如果用上面的方式调用 apply, 你很可能会遇到方法参数个数越界的问题. 当你对一个方法传入非常多的参数 (比如超过1W多个参数) 时, 就非常有可能会导致越界问题, 这个临界值是根据不同的 JavaScript 引擎而定的 (JavaScript 核心中已经做了硬编码 argument limit of 65536). 有些引擎会抛出异常.  更糟糕的是其他引擎会直接限制传入到方法的参数个数,导致参数丢失. (举个例子: 如果某个引擎限制了方法参数最多为4个 [实际真正的参数个数限制当然要高得多了, 这里只是打个比方], 上面的代码中, 真正通过 apply 传到目标方法中的参数为 5, 6, 2, 3, 而不是完整的 numbers 数组.) 如果你的参数数组可能非常大, 那么推荐使用下面这种策略来处理: 将参数数组切块后循环传入目标方法:

function minOfArray(arr) {
  var min = Infinity;
  var QUANTUM = 32768;

  for (var i = 0, len = arr.length; i < len; i += QUANTUM) {
    var submin = Math.min.apply(null, arr.slice(i, Math.min(i + QUANTUM, len)));
    min = Math.min(submin, min);
  }

  return min;
}

var min = minOfArray([5, 6, 2, 3, 7]);
 
 

Using apply in "monkey-patching"

Apply can be the best way to monkey-patch a builtin function of Firefox, or JS libraries. Given someobject.foo function, you can modify the function in a somewhat hacky way, like so:

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.
}
  
  
 
 
 
 
 
 
 
 

This method is especially handy where you want to debug events, or interface with something that has no API like the various .on([event]... events, such as those usable on the Devtools Inspector).

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值