aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/web/javascript/reference/global_objects/function/apply/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'files/zh-cn/web/javascript/reference/global_objects/function/apply/index.html')
-rw-r--r--files/zh-cn/web/javascript/reference/global_objects/function/apply/index.html219
1 files changed, 219 insertions, 0 deletions
diff --git a/files/zh-cn/web/javascript/reference/global_objects/function/apply/index.html b/files/zh-cn/web/javascript/reference/global_objects/function/apply/index.html
new file mode 100644
index 0000000000..de53da11e7
--- /dev/null
+++ b/files/zh-cn/web/javascript/reference/global_objects/function/apply/index.html
@@ -0,0 +1,219 @@
+---
+title: Function.prototype.apply()
+slug: Web/JavaScript/Reference/Global_Objects/Function/apply
+tags:
+ - Function
+ - JavaScript
+ - Method
+translation_of: Web/JavaScript/Reference/Global_Objects/Function/apply
+---
+<div>{{JSRef}}</div>
+
+<p><strong><code>apply()</code></strong> 方法调用一个具有给定<code>this</code>值的函数,以及以一个数组(或<a href="/zh-CN/docs/Web/JavaScript/Guide/Indexed_collections#Working_with_array-like_objects">类数组对象</a>)的形式提供的参数。</p>
+
+<div class="note"><strong>注意:</strong><span style="line-height: 1.5;">call()方法的作用和 apply() 方法类似,区别就是<code>call()</code>方法接受的是<strong>参数列表</strong>,而<code>apply()</code>方法接受的是<strong>一个参数数组</strong>。</span></div>
+
+<div>{{EmbedInteractiveExample("pages/js/function-apply.html")}}</div>
+
+
+
+<h2 id="Syntax" name="Syntax">语法</h2>
+
+<pre class="syntaxbox notranslate"><code><em>func</em>.apply(<em>thisArg</em><em>, [</em><em>argsArray</em>])</code></pre>
+
+<h3 id="Parameters" name="Parameters">参数</h3>
+
+<dl>
+ <dt><code>thisArg</code></dt>
+ <dd>必选的。在 <em><code>func</code></em> 函数运行时使用的 <code>this</code> 值。请注意,<code>this</code>可能不是该方法看到的实际值:如果这个函数处于{{jsxref("Strict_mode", "非严格模式", "", 1)}}下,则指定为 <code>null</code> 或 <code>undefined</code> 时会自动替换为指向全局对象,原始值会被包装。</dd>
+ <dt><code>argsArray</code></dt>
+ <dd>可选的。一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 <code>func</code> 函数。如果该参数的值为 {{jsxref("null")}} 或  {{jsxref("undefined")}},则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。 {{anch("Browser_compatibility", "浏览器兼容性")}} 请参阅本文底部内容。</dd>
+</dl>
+
+<h3 id="返回值">返回值</h3>
+
+<p>调用有指定<code><strong>this</strong></code>值和参数的函数的结果。</p>
+
+<h2 id="Description" name="Description">描述</h2>
+
+<p><span style="line-height: 1.5;">在调用一个存在的函数时,你可以为其指定一个 <code>this</code> 对象。 <code>this</code></span> <span style="line-height: 1.5;">指当前对象,也就是正在调用这个函数的对象。 使用 <code>apply</code>, 你可以只写一次这个方法然后在另一个对象中继承它,而不用在新对象中重复写该方法。</span></p>
+
+<p><code>apply</code> 与 {{jsxref("Function.call", "call()")}} 非常相似,不同之处在于提供参数的方式。<code style="font-size: 14px;">apply</code> 使用参数数组而不是一组参数列表。<code>apply</code> 可以使用数组字面量(array literal)<span style="line-height: 1.5;">,如 </span><code>fun.apply(this, ['eat', 'bananas'])</code><span style="line-height: 1.5;">,或数组对象,</span><span style="line-height: 1.5;"> 如  </span><code>fun.apply(this, new Array('eat', 'bananas'))</code><span style="line-height: 1.5;">。</span></p>
+
+<p>你也可以使用 {{jsxref("Functions/arguments", "arguments")}}对象作为 <code>argsArray</code> 参数。 <code>arguments</code> 是一个函数的局部变量。 它可以被用作被调用对象的所有未指定的参数。 这样,你在使用apply函数的时候就不需要知道被调用对象的所有参数。 你可以使用arguments来把所有的参数传递给被调用对象。 被调用对象接下来就负责处理这些参数。</p>
+
+<p>从 ECMAScript 第5版开始,可以使用任何种类的类数组对象,就是说只要有一个 <code>length</code> 属性和<code>(0..length-1)</code>范围的整数属性。例如现在可以使用 {{domxref("NodeList")}} 或一个自己定义的类似 <code>{'length': 2, '0': 'eat', '1': 'bananas'}</code> 形式的对象。</p>
+
+<div class="note">
+<p>需要注意:Chrome 14 以及 Internet Explorer 9 仍然不接受类数组对象。如果传入类数组对象,它们会抛出异常。</p>
+</div>
+
+<h2 id="Examples" name="Examples">示例</h2>
+
+<h3 id="用_apply_将数组各项添加到另一个数组">用 <code>apply</code> 将数组各项添加到另一个数组</h3>
+
+<p>我们可以使用<code>push</code>将元素追加到数组中。由于push接受可变数量的参数,所以也可以一次追加多个元素。</p>
+
+<p>但是,如果<code>push</code>的参数是数组,它会将该数组作为单个元素添加,而不是将这个数组内的每个元素添加进去,因此我们最终会得到一个数组内的数组。如果不想这样呢?<code>concat</code>符合我们的需求,但它并不是将元素添加到现有数组,而是创建并返回一个新数组。 然而我们需要将元素追加到现有数组......那么怎么做好?难道要写一个循环吗?别当然不是!</p>
+
+<p><code>apply</code>正派上用场!</p>
+
+<pre class="brush: js notranslate">var array = ['a', 'b'];
+var elements = [0, 1, 2];
+array.push.apply(array, elements);
+console.info(array); // ["a", "b", 0, 1, 2]
+</pre>
+
+<h3 id="apply_and_built-in_functions" name="apply_and_built-in_functions">使用<code>apply</code>和内置函数</h3>
+
+<p>对于一些需要写循环以便历数组各项的需求,我们可以用<code>apply</code>完成以避免循环。</p>
+
+<p>下面是示例,我们将用<code>Math.max</code>/<code>Math.min</code>求得数组中的最大/小值。</p>
+
+<pre class="brush: js notranslate">/* 找出数组中最大/小的数字 */
+var numbers = [5, 6, 2, 3, 7];
+
+/* 使用Math.min/Math.max以及apply 函数时的代码 */
+var max = Math.max.apply(null, numbers); /* 基本等同于 Math.max(numbers[0], ...) 或 Math.max(5, 6, ..) */
+var min = Math.min.apply(null, numbers);
+
+/* 对比:简单循环算法 */
+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>注意:如果按上面方式调用<code>apply</code>,有超出JavaScript引擎参数长度上限的风险。一个方法传入过多参数(比如一万个)时的后果在不同JavaScript 引擎中表现不同。(JavaScriptCore引擎中有被硬编码的<a class="link-https" href="https://bugs.webkit.org/show_bug.cgi?id=80797"> 参数个数上限:65536</a>)。这是因为此限制(实际上也是任何用到超大栈空间的行为的自然表现)是不明确的。一些引擎会抛出异常,更糟糕的是其他引擎会直接限制传入到方法的参数个数,导致参数丢失。比如:假设某个引擎的方法参数上限为4(实际上限当然要高得多), 这种情况下,上面的代码执行后, 真正被传递到 <code>apply</code>的参数为 <code>5, 6, 2, 3</code> ,而不是完整的数组。</p>
+
+<p>如果你的参数数组可能非常大,那么推荐使用下面这种混合策略:将数组切块后循环传入目标方法:</p>
+
+<pre class="brush: js notranslate">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>
+
+<h3 id="Using_apply_to_chain_constructors" name="Using_apply_to_chain_constructors">使用apply来链接构造器</h3>
+
+<p>你可以使用apply来链接一个对象<a href="/zh-CN/docs/JavaScript/Reference/Operators/new" title="JavaScript/Reference/Operators/new">构造器</a>,类似于Java。在接下来的例子中我们会创建一个全局<a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Function" title="JavaScript/Reference/Global_Objects/Function"><code>Function</code></a> <span style="color: #000000; display: inline !important; float: none; font-family: 'microsoft yahei'; font-size: 18px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 28.8px; text-align: left; text-indent: 0px; text-transform: none; white-space: normal;">对象的</span><span style="color: #000000; font-family: 'microsoft yahei'; font-size: 18px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 28.8px; text-align: left; text-indent: 0px; text-transform: none; white-space: normal;">construct</span><span style="color: #000000; font-family: 'microsoft yahei'; font-size: 18px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 1.6; text-align: left; text-indent: 0px; text-transform: none; white-space: normal;">方法</span> ,来使你能够在构造器中使用一个类数组对象而非参数列表。</p>
+
+<pre class="brush: js notranslate">Function.prototype.construct = function (aArgs) {
+ var oNew = Object.create(this.prototype);
+ this.apply(oNew, aArgs);
+ return oNew;
+};
+</pre>
+
+<div class="note">
+<p><strong>注意:</strong> 上面使用的<code>Object.create()</code>方法相对来说比较新。另一种可选的方法,请考虑如下替代方法:</p>
+
+<p>Using {{jsxref("Object/__proto__", "Object.__proto__")}}:</p>
+
+<pre class="brush: js notranslate">Function.prototype.construct = function (aArgs) {
+ var oNew = {};
+ oNew.__proto__ = this.prototype;
+ this.apply(oNew, aArgs);
+ return oNew;
+};</pre>
+
+<p>使用闭包:</p>
+
+<pre class="brush: js notranslate" style="font-style: normal;">Function.prototype.construct = function(aArgs) {
+ var fConstructor = this, fNewConstr = function() {
+ fConstructor.apply(this, aArgs);
+ };
+ fNewConstr.prototype = fConstructor.prototype;
+ return new fNewConstr();
+};</pre>
+
+<p class="brush: js" style="font-style: normal;">使用 Function 构造器:</p>
+
+<pre class="brush: js notranslate">Function.prototype.construct = function (aArgs) {
+ var fNewConstr = new Function("");
+ fNewConstr.prototype = this.prototype;
+ var oNew = new fNewConstr();
+ this.apply(oNew, aArgs);
+ return oNew;
+};</pre>
+</div>
+
+<p>使用示例:</p>
+
+<pre class="brush: js notranslate">function MyConstructor (arguments) {
+    for (var nProp = 0; nProp &lt; arguments.length; nProp++) {
+        this["property" + nProp] = arguments[nProp];
+    }
+}
+
+var myArray = [4, "Hello world!", false];
+var myInstance = new MyConstructor(myArray); //Fix MyConstructor.construct is not a function
+
+console.log(myInstance.property1);                // logs "Hello world!"
+console.log(myInstance instanceof MyConstructor); // logs "true"
+console.log(myInstance.constructor);              // logs "MyConstructor"
+</pre>
+
+<div class="note"><strong>注意:</strong> 这个非native的<code>Function.construct</code>方法无法和一些native构造器(例如<a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Date" title="JavaScript/Reference/Global_Objects/Date"><code>Date</code></a>)一起使用。 在这种情况下你必须使用<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>方法(例如,想象有如下一个数组要用在Date构造器中: <code>[2012, 11, 4]</code>;这时你需要这样写: <code>new (Function.prototype.bind.apply(Date, [null].concat([2012, 11, 4])))()</code> – -无论如何这不是最好的实现方式并且也许不该用在任何生产环境中).</div>
+
+<h2 id="规范" style="margin-bottom: 20px; line-height: 30px;">规范</h2>
+
+<table class="standard-table">
+ <tbody>
+ <tr>
+ <th scope="col">Specification</th>
+ <th scope="col">Status</th>
+ <th scope="col">Comment</th>
+ </tr>
+ <tr>
+ <td>{{SpecName('ES3')}}</td>
+ <td>{{Spec2('ES3')}}</td>
+ <td>Initial definition. Implemented in JavaScript 1.3.</td>
+ </tr>
+ <tr>
+ <td>{{SpecName('ES5.1', '#sec-15.3.4.3', 'Function.prototype.apply')}}</td>
+ <td>{{Spec2('ES5.1')}}</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>{{SpecName('ES6', '#sec-function.prototype.apply', 'Function.prototype.apply')}}</td>
+ <td>{{Spec2('ES6')}}</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>{{SpecName('ESDraft', '#sec-function.prototype.apply', 'Function.prototype.apply')}}</td>
+ <td>{{Spec2('ESDraft')}}</td>
+ <td></td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="浏览器兼容性" style="margin-bottom: 20px; line-height: 30px;">浏览器兼容性</h2>
+
+<div class="hidden">
+<p>The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</p>
+</div>
+
+<p>{{Compat("javascript.builtins.Function.apply")}}</p>
+
+<h2 id="See_also" name="See_also" style="margin-bottom: 20px; line-height: 30px;">相关链接</h2>
+
+<ul>
+ <li>{{jsxref("Functions_and_function_scope/arguments", "arguments ")}} object</li>
+ <li>{{jsxref("Function.prototype.bind()")}}</li>
+ <li>{{jsxref("Function.prototype.call()")}}</li>
+ <li>{{jsxref("Functions", "Functions and function scope", "", 1)}}</li>
+ <li>{{jsxref("Reflect.apply()")}}</li>
+</ul>