Apply your JS skills to key Mozilla projects as an MDN Fellow! http://mzl.la/MDNFellowship

mozilla

Revision 539377 of Function.prototype.apply()

  • Revision slug: JavaScript/Reference/Global_Objects/Function/apply
  • Revision title: Function.prototype.apply method
  • Revision id: 539377
  • Created:
  • Creator: endlesswind
  • Is current revision? No
  • Comment

Revision Content

概述

在使用一个指定的this值和若干个指定的参数值的前提下调用某个函数或方法.

注:该方法的作用和call()方法类似,只有一个区别就是,call()方法接受的是若干个参数的列表,而apply()方法接受的是一个包含多个参数的数组(或类数组对象).
Method of Function
Implemented in JavaScript 1.3
ECMAScript Edition ECMA-262 3rd Edition

语法

fun.apply(thisArg[, argsArray])

参数

thisArg
fun函数运行时指定的this.需要注意的是,指定的this值并不一定是该函数执行时真正的this值,如果这个函数处于非严格模式下,则指定为nullundefinedthis值会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象.
argsArray
一个数组对象或者类数组对象,其中的数组元素将作为单独的参数传给fun函数.如果该参数的值为nullundefined,则表示不需要传入任何参数.
{{ js_minversion_note("1.8.5", "从JavaScript 1.8.5 (Firefox 4)开始,根据ES5规范,argsArray参数可以是一个数组或者任意类数组对象,在这之前,实现的是ES3规范,其中argsArray参数只能是数组对象或者是arguments对象(也是类数组对象)") }}

查看{{ bug(562448) }}了解这个变化的详情.

描述

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

apply与call非常相似,不同在于所提供的参数类型. apply使用参数数组而不是 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.

Since ECMAScript 5th Edition you can also use any kind of object which is array like, so in practice this means it's going to have a property length and integer properties in the range [0...length). As an example you can now use a NodeList or a own custom object like {'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];
}

But beware: in using apply this way, you run the risk of exceeding the JavaScript engine's argument length limit. The consequences of applying a function with too many arguments (think more than tens of thousands of arguments) vary across engines (JavaScriptCore has hard-coded argument limit of 65536), because the limit (indeed even the nature of any excessively-large-stack behavior) is unspecified. Some engines will throw an exception. More perniciously, others will arbitrarily limit the number of arguments actually passed to the applied function. (To illustrate this latter case: if such an engine had a limit of four arguments [actual limits are of course significantly higher], it would be as if the arguments 5, 6, 2, 3 had been passed to apply in the examples above, rather than the full array.) If your value array might grow into the tens of thousands, use a hybrid strategy: apply your function to chunks of the array at a time:

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

相关链接

Revision Source

<h2 id="Summary" name="Summary">概述</h2>
<p>在使用一个指定的<code>this</code>值和若干个指定的参数值的前提下调用某个函数或方法.</p>
<div class="note">
 <strong>注:</strong>该方法的作用和<a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Function/call" title="/zh-CN/docs/JavaScript/Reference/Global_Objects/Function/call"><code>call()</code></a>方法类似,只有一个区别就是,<code>call()方法接受的是若干个参数的列表,而</code><code>apply()</code>方法接受的是一个包含多个参数的数组(或类数组对象).</div>
<table class="standard-table">
 <thead>
  <tr>
   <th class="header" colspan="2" scope="row">Method of <a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Function" title="JavaScript/Reference/Global_Objects/Function">Function</a></th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>Implemented in</td>
   <td>JavaScript 1.3</td>
  </tr>
  <tr>
   <td>ECMAScript Edition</td>
   <td>ECMA-262 3rd Edition</td>
  </tr>
 </tbody>
</table>
<h2 id="Syntax" name="Syntax">语法</h2>
<pre class="syntaxbox">
<code><em>fun</em>.apply(<em>thisArg</em>[, <em>argsArray</em>])</code></pre>
<h3 id="Parameters" name="Parameters">参数</h3>
<dl>
 <dt>
  <code>thisArg</code></dt>
 <dd>
  在<em><code>fun函数运行时指定的</code></em><code>this</code><em><code>值</code></em>.需要注意的是,指定的<code>this</code>值并不一定是该函数执行时真正的<code>this</code>值,如果这个函数处于<a class="new" href="../../../../../../zh-CN/docs/JavaScript/Reference/Functions_and_function_scope/Strict_mode" title="JavaScript/Strict mode">非严格模式下</a>,则指定为<code>null</code>和<code>undefined</code>的<code>this值会自动指向</code>全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的<code>this</code>会指向该原始值的自动包装对象.</dd>
 <dt>
  <code>argsArray</code></dt>
 <dd>
  一个数组对象或者类数组对象,其中的数组元素将作为单独的参数传给<code>fun</code>函数.如果该参数的值<code>为null</code>或<a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/undefined" title="JavaScript/Reference/Global_Properties/undefined">undefined</a>,则表示不需要传入任何参数.</dd>
</dl>
<div>
 {{ js_minversion_note("1.8.5", "从JavaScript 1.8.5 (Firefox 4)开始,根据<code>ES5</code>规范,<code>argsArray参数可以是一个数组或者任意类数组对象,在这之前,实现的是ES3规范,其中</code>argsArray参数只能是数组对象或者<code>是arguments</code>对象(也是类数组对象)") }}</div>
<p>查看{{ bug(562448) }}了解这个变化的详情.</p>
<h2 id="Description" name="Description">描述</h2>
<p><span style="line-height: 1.5;">在调用一个存在的函数时, 你可以为其指定一个this对象. this指当前对象, 也就是正在调用这个函数的对象. 使用apply, 你可以只写一次这个方法然后在另一个对象中继承它,而不用在新对象中重复写该方法.</span></p>
<p><code>apply与</code><a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Function/call" style="font-family: 'Courier New', 'Andale Mono', monospace; line-height: normal;" title="JavaScript/Reference/Global_Objects/Function/call">call</a><code style="font-size: 14px;">非常相似,不同在于所提供的参数类型. apply使用参数数组而不是</code><span style="line-height: 1.5;">&nbsp;named set of parameters. 使用 </span><code style="font-size: 14px;">apply</code><span style="line-height: 1.5;">, 可以使用</span>array literal<span style="line-height: 1.5;">形式,例如, </span><code style="font-size: 14px;"><em>fun</em>.apply(this, ['eat', 'bananas'])</code><span style="line-height: 1.5;">, 或者数组对象形式</span><span style="line-height: 1.5;">, 例如, </span><code style="font-size: 14px;"><em>fun</em>.apply(this, new Array('eat', 'bananas'))</code><span style="line-height: 1.5;">.</span></p>
<p>你也可以使用&nbsp;<code><a href="/zh-CN/docs/JavaScript/Reference/Functions_and_function_scope/arguments" title="JavaScript/Reference/Functions_and_function_scope/arguments">arguments</a></code>&nbsp;对象作为&nbsp;<code>argsArray</code> 参数. <code>arguments</code> 是一个函数的局部变量. 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 <code>apply</code> method. You can use <code>arguments</code> to pass all the arguments to the called object. The called object is then responsible for handling the arguments.</p>
<p>Since ECMAScript 5th Edition you can also use any kind of object which is array like, so in practice this means it's going to have a property <code>length</code> and integer properties in the range <code>[0...length)</code>. As an example you can now use a <a href="/zh-CN/docs/DOM/NodeList" title="DOM/NodeList">NodeList</a> or a own custom object like <code>{'length': 2, '0': 'eat', '1': 'bananas'}</code>.</p>
<div>
 {{ note("Most browsers, including Chrome 14 and Internet Explorer 9, still do not accept array like objects and will throw an exception.") }}</div>
<h2 id="Examples" name="Examples">示例</h2>
<h3 id="Using_apply_to_chain_constructors" name="Using_apply_to_chain_constructors">Using <code>apply</code> to chain constructors</h3>
<p>You can use <code>apply</code> to chain <a href="/zh-CN/docs/JavaScript/Reference/Operators/new" title="JavaScript/Reference/Operators/new">constructors</a> for an object, similar to Java. In the following example we will create a global <a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Function" title="JavaScript/Reference/Global_Objects/Function"><code>Function</code></a> method called <code>construct</code>, which will make you able to use an array-like object with a constructor instead of an arguments list.</p>
<pre class="brush: js">
Function.prototype.construct = function (aArgs) {
    var fConstructor = this, fNewConstr = function () { fConstructor.apply(this, aArgs); };
    fNewConstr.prototype = fConstructor.prototype;
    return new fNewConstr();
};</pre>
<p>Example usage:</p>
<pre class="brush: js">
function MyConstructor () {
    for (var nProp = 0; nProp &lt; 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"</pre>
<div class="note">
 <strong>Note:</strong> This non-native <code>Function.construct</code> method will not work with some native constructors (like <a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Date" title="JavaScript/Reference/Global_Objects/Date"><code>Date</code></a>, for example). In these cases you have to use the <a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Function/bind#Bound_functions_used_as_constructors" title="JavaScript/Reference/Global_Objects/Function/bind#Bound_functions_used_as_constructors"><code>Function.bind</code></a> method (for example, imagine to have an array like the following, to be used with <code>Date</code> constructor: <code>[2012, 11, 4]</code>; in this case you have to write something like: <code>new (Function.prototype.bind.apply(Date, [null].concat([2012, 11, 4])))()</code> – anyhow this is not the best way to do things and probably should not be used in any production environment).</div>
<h3 id="apply_and_built-in_functions" name="apply_and_built-in_functions"><code>apply</code> and built-in functions</h3>
<p>Clever usage of <code>apply</code> 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.</p>
<pre class="brush: js">
/* 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 &lt; numbers.length; i++) {
  if (numbers[i] &gt; max)
    max = numbers[i];
  if (numbers[i] &lt; min) 
    min = numbers[i];
}</pre>
<p>But beware: in using <code>apply</code> this way, you run the risk of exceeding the JavaScript engine's argument length limit. The consequences of applying a function with too many arguments (think more than tens of thousands of arguments) vary across engines (JavaScriptCore has hard-coded <a class="link-https" href="https://bugs.webkit.org/show_bug.cgi?id=80797">argument limit of 65536</a>), because the limit (indeed even the nature of any excessively-large-stack behavior) is unspecified. Some engines will throw an exception. More perniciously, others will arbitrarily limit the number of arguments actually passed to the applied function. (To illustrate this latter case: if such an engine had a limit of four arguments [actual limits are of course significantly higher], it would be as if the arguments <code>5, 6, 2, 3</code> had been passed to <code>apply</code> in the examples above, rather than the full array.) If your value array might grow into the tens of thousands, use a hybrid strategy: apply your function to chunks of the array at a time:</p>
<pre class="brush: js">
function minOfArray(arr) {
  var min = Infinity;
  var QUANTUM = 32768;

  for (var i = 0, len = arr.length; i &lt; 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]);</pre>
<h2 id="See_also" name="See_also">相关链接</h2>
<ul>
 <li><a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Function/call" title="JavaScript/Reference/Global_Objects/Function/call">call</a>, <a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Function/bind" title="JavaScript/Reference/Global_Objects/Function/bind">bind</a>, <a href="/zh-CN/docs/JavaScript/Reference/Functions_and_function_scope/arguments" title="JavaScript/Reference/Functions_and_function_scope/arguments">arguments</a></li>
</ul>
Revert to this revision