diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
commit | 33058f2b292b3a581333bdfb21b8f671898c5060 (patch) | |
tree | 51c3e392513ec574331b2d3f85c394445ea803c6 /files/zh-cn/web/javascript/reference/global_objects/function | |
parent | 8b66d724f7caf0157093fb09cfec8fbd0c6ad50a (diff) | |
download | translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.gz translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.bz2 translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.zip |
initial commit
Diffstat (limited to 'files/zh-cn/web/javascript/reference/global_objects/function')
14 files changed, 1969 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 < numbers.length; i++) { + if (numbers[i] > max) + max = numbers[i]; + if (numbers[i] < 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 < 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 < 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> diff --git a/files/zh-cn/web/javascript/reference/global_objects/function/arguments/index.html b/files/zh-cn/web/javascript/reference/global_objects/function/arguments/index.html new file mode 100644 index 0000000000..a0c93f29f3 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/function/arguments/index.html @@ -0,0 +1,125 @@ +--- +title: Function.arguments +slug: Web/JavaScript/Reference/Global_Objects/Function/arguments +translation_of: Web/JavaScript/Reference/Global_Objects/Function/arguments +--- +<div>{{JSRef}} {{deprecated_header}}</div> + +<p><code><strong><em>function</em>.arguments</strong></code> 属性代表传入函数的实参,它是一个类数组对象。</p> + +<h2 id="描述">描述</h2> + +<p><code><em>function</em>.arguments</code> 已经被废弃了, 现在推荐的做法是使用函数内部可用的 {{jsxref("Functions/arguments", "arguments")}} 对象来访问函数的实参。</p> + +<p>在函数递归调用的时候(在某一刻同一个函数运行了多次,也就是有多套实参),那么 <code>arguments</code> 属性的值是最近一次该函数调用时传入的实参,下面的示例有演示。</p> + +<p>如果函数不在执行期间,那么该函数的 <code>arguments</code> 属性的值是 <code>null</code>。</p> + +<h2 id="示例">示例</h2> + +<pre class="brush: js">function f(n) { g(n - 1); } + +function g(n) { + console.log('before: ' + g.arguments[0]); + if (n > 0) { f(n); } + console.log('after: ' + g.arguments[0]); +} + +f(2); + +console.log('函数退出后的 arguments 属性值:' + g.arguments); + +// 输出: + +// before: 1 +// before: 0 +// after: 0 +// after: 1 +// 函数退出后的 arguments 属性值:null +</pre> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">规范名称</th> + <th scope="col">规范状态</th> + <th scope="col">备注</th> + </tr> + <tr> + <td>{{SpecName('ES1')}}</td> + <td>{{Spec2('ES1')}}</td> + <td>arguments 属性首次实现于 JavaScript 1.0,首次添加进规范是在 ES1,在 ES3 中被删除。</td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-10.6', 'arguments object')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td>{{jsxref("Functions/arguments", "arguments")}}</td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-arguments-object', 'arguments object')}}</td> + <td>{{Spec2('ES6')}}</td> + <td>{{jsxref("Functions/arguments", "arguments")}}</td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + +<div>{{CompatibilityTable}}</div> + +<div id="compat-desktop"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Chrome</th> + <th>Firefox (Gecko)</th> + <th>Internet Explorer</th> + <th>Opera</th> + <th>Safari</th> + </tr> + <tr> + <td>Basic support</td> + <td>{{CompatVersionUnknown}}</td> + <td>{{CompatVersionUnknown}}</td> + <td>{{CompatVersionUnknown}}</td> + <td>{{CompatVersionUnknown}}</td> + <td>{{CompatVersionUnknown}}</td> + </tr> + </tbody> +</table> +</div> + +<div id="compat-mobile"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Android</th> + <th>Chrome for Android</th> + <th>Firefox Mobile (Gecko)</th> + <th>IE Mobile</th> + <th>Opera Mobile</th> + <th>Safari Mobile</th> + </tr> + <tr> + <td>Basic support</td> + <td>{{CompatVersionUnknown}}</td> + <td>{{CompatVersionUnknown}}</td> + <td>{{CompatVersionUnknown}}</td> + <td>{{CompatVersionUnknown}}</td> + <td>{{CompatVersionUnknown}}</td> + <td>{{CompatVersionUnknown}}</td> + </tr> + </tbody> +</table> +</div> + +<h2 id="相关链接">相关链接</h2> + +<ul> + <li>{{jsxref("Functions/arguments", "arguments")}}</li> + <li>{{jsxref("Functions", "函数和函数的作用域", "", 1)}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/global_objects/function/arity/index.html b/files/zh-cn/web/javascript/reference/global_objects/function/arity/index.html new file mode 100644 index 0000000000..d8e8668ca2 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/function/arity/index.html @@ -0,0 +1,16 @@ +--- +title: Function.arity +slug: Web/JavaScript/Reference/Global_Objects/Function/arity +translation_of: Archive/Web/JavaScript/Function.arity +--- +<div> +<div>{{JSRef("Global_Objects", "Function")}} {{obsolete_header}}</div> +</div> + +<h2 id="Summary" name="Summary">概述</h2> + +<p>返回一个函数的形参数量.</p> + +<h2 id="Description" name="Description">描述</h2> + +<p class="note"><code>arity</code>是一个古老的已经没有浏览器支持的属性,你应该使用<code><a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Function/length" title="JavaScript/Reference/Global_Objects/Function/length">Function.prototype.length</a></code>属性来代替.</p> diff --git a/files/zh-cn/web/javascript/reference/global_objects/function/bind/index.html b/files/zh-cn/web/javascript/reference/global_objects/function/bind/index.html new file mode 100644 index 0000000000..fbabcdfc13 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/function/bind/index.html @@ -0,0 +1,324 @@ +--- +title: Function.prototype.bind() +slug: Web/JavaScript/Reference/Global_Objects/Function/bind +tags: + - ECMAScript 2015 + - ECMAScript 5 + - Function + - JavaScript + - Method + - polyfill +translation_of: Web/JavaScript/Reference/Global_Objects/Function/bind +--- +<div>{{JSRef}}</div> + +<p><code><strong>bind()</strong></code> 方法创建一个新的函数,在 <code>bind()</code> 被调用时,这个新函数的 <code>this</code> 被指定为 <code>bind()</code> 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。</p> + +<div>{{EmbedInteractiveExample("pages/js/function-bind.html", "taller")}}</div> + + + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox notranslate"><code><var>function</var></code>.bind(<var>thisArg</var>[, <var>arg1</var>[, <var>arg2</var>[, ...]]])</pre> + +<h3 id="参数">参数</h3> + +<dl> + <dt><code>thisArg</code></dt> + <dd>调用绑定函数时作为 <code>this</code> 参数传递给目标函数的值。 如果使用{{jsxref("Operators/new", "new")}}运算符构造绑定函数,则忽略该值。当使用 <code>bind</code> 在 <code>setTimeout</code> 中创建一个函数(作为回调提供)时,作为 <code>thisArg</code> 传递的任何原始值都将转换为 <code>object</code>。如果 <code>bind</code> 函数的参数列表为空,或者<code>thisArg</code>是<code>null</code>或<code>undefined</code>,执行作用域的 <code>this</code> 将被视为新函数的 <code>thisArg</code>。</dd> + <dt><code>arg1, arg2, ...</code></dt> + <dd>当目标函数被调用时,被预置入绑定函数的参数列表中的参数。</dd> +</dl> + +<h3 id="返回值">返回值</h3> + +<p>返回一个原函数的拷贝,并拥有指定的 <strong><code>this</code></strong> 值和初始参数。</p> + +<h2 id="描述">描述</h2> + +<div><strong>bind()</strong> 函数会创建一个新的<strong>绑定函数</strong>(<strong>bound function</strong>,BF)。绑定函数是一个 exotic function object(怪异函数对象,ECMAScript 2015 中的术语),它包装了原函数对象。调用<strong>绑定函数</strong>通常会导致执行<strong>包装函数</strong>。<br> +<strong>绑定函数</strong>具有以下内部属性:</div> + +<div></div> + +<div> +<ul> + <li><strong>[[BoundTargetFunction]]</strong> - 包装的函数对象</li> + <li><strong>[[BoundThis]]</strong> - 在调用包装函数时始终作为 <strong>this</strong> 值传递的值。</li> + <li><strong>[[BoundArguments]]</strong> - 列表,在对包装函数做任何调用都会优先用列表元素填充参数列表。</li> + <li><strong>[[Call]]</strong> - 执行与此对象关联的代码。通过函数调用表达式调用。内部方法的参数是一个<strong>this</strong>值和一个包含通过调用表达式传递给函数的参数的列表。</li> +</ul> + +<p>当调用绑定函数时,它调用 <strong>[[BoundTargetFunction]]</strong> 上的内部方法 <strong>[[Call]]</strong>,就像这样 <strong>Call(<em>boundThis</em>, <em>args</em>)</strong>。其中,<strong>boundThis</strong> 是 <strong>[[BoundThis]]</strong>,<strong>args</strong> 是 <strong>[[BoundArguments]]</strong> 加上通过函数调用传入的参数列表。</p> +</div> + +<div> +<p>绑定函数也可以使用 {{jsxref("Operators/new", "new")}} 运算符构造,它会表现为目标函数已经被构建完毕了似的。提供的 <code>this</code> 值会被忽略,但前置参数仍会提供给模拟函数。</p> +</div> + +<h2 id="示例">示例</h2> + +<h3 id="创建绑定函数">创建绑定函数</h3> + +<p><code>bind()</code> 最简单的用法是创建一个函数,不论怎么调用,这个函数都有同样的 <strong><code>this</code></strong> 值。JavaScript新手经常犯的一个错误是将一个方法从对象中拿出来,然后再调用,期望方法中的 <code>this</code> 是原来的对象(比如在回调中传入这个方法)。如果不做特殊处理的话,一般会丢失原来的对象。基于这个函数,用原始的对象创建一个绑定函数,巧妙地解决了这个问题:</p> + +<pre class="brush: js notranslate">this.x = 9; // 在浏览器中,this 指向全局的 "window" 对象 +var module = { + x: 81, + getX: function() { return this.x; } +}; + +module.getX(); // 81 + +var retrieveX = module.getX; +retrieveX(); +// 返回 9 - 因为函数是在全局作用域中调用的 + +// 创建一个新函数,把 'this' 绑定到 module 对象 +// 新手可能会将全局变量 x 与 module 的属性 x 混淆 +var boundGetX = retrieveX.bind(module); +boundGetX(); // 81 +</pre> + +<h3 id="偏函数">偏函数</h3> + +<p><code>bind()</code> 的另一个最简单的用法是使一个函数拥有预设的初始参数。只要将这些参数(如果有的话)作为 <code>bind()</code> 的参数写在 <code>this</code> 后面。当绑定函数被调用时,这些参数会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们后面。</p> + +<pre class="brush: js notranslate">function list() { + return Array.prototype.slice.call(arguments); +} + +function addArguments(arg1, arg2) { + return arg1 + arg2 +} + +var list1 = list(1, 2, 3); // [1, 2, 3] + +var result1 = addArguments(1, 2); // 3 + +// 创建一个函数,它拥有预设参数列表。 +var leadingThirtysevenList = list.bind(null, 37); + +// 创建一个函数,它拥有预设的第一个参数 +var addThirtySeven = addArguments.bind(null, 37); + +var list2 = leadingThirtysevenList(); +// [37] + +var list3 = leadingThirtysevenList(1, 2, 3); +// [37, 1, 2, 3] + +var result2 = addThirtySeven(5); +// 37 + 5 = 42 + +var result3 = addThirtySeven(5, 10); +// 37 + 5 = 42 ,第二个参数被忽略 +</pre> + +<h3 id="配合_setTimeout">配合 <code>setTimeout</code></h3> + +<p>在默认情况下,使用 {{ domxref("window.setTimeout()") }} 时,<code>this</code> 关键字会指向 {{ domxref("window") }} (或 <code>global</code>)对象。当类的方法中需要 <code>this</code> 指向类的实例时,你可能需要显式地把 <code>this</code> 绑定到回调函数,就不会丢失该实例的引用。</p> + +<pre class="brush: js notranslate"><code>function LateBloomer() { + this.petalCount = Math.ceil(Math.random() * 12) + 1; +} + +// 在 1 秒钟后声明 bloom +LateBloomer.prototype.bloom = function() { + window.setTimeout(this.declare.bind(this), 1000); +}; + +LateBloomer.prototype.declare = function() { + console.log('I am a beautiful flower with ' + + this.petalCount + ' petals!'); +}; + +var flower = new LateBloomer(); +flower.bloom(); // 一秒钟后, 调用 'declare' 方法</code></pre> + +<h3 id="作为构造函数使用的绑定函数">作为构造函数使用的绑定函数</h3> + +<div class="warning"> +<p><strong>警告</strong> :这部分演示了 JavaScript 的能力并且记录了 <code>bind()</code> 的超前用法。以下展示的方法并不是最佳的解决方案,且可能不应该用在任何生产环境中。</p> +</div> + +<p>绑定函数自动适应于使用 {{jsxref("Operators/new", "new")}} 操作符去构造一个由目标函数创建的新实例。当一个绑定函数是用来构建一个值的,原来提供的 <code>this</code> 就会被忽略。不过提供的参数列表仍然会插入到构造函数调用时的参数列表之前。</p> + +<pre class="brush: js notranslate">function Point(x, y) { + this.x = x; + this.y = y; +} + +Point.prototype.toString = function() { + return this.x + ',' + this.y; +}; + +var p = new Point(1, 2); +p.toString(); // '1,2' + +var emptyObj = {}; +var YAxisPoint = Point.bind(emptyObj, 0/*x*/); + +// 本页下方的 polyfill 不支持运行这行代码, +// 但使用原生的 bind 方法运行是没问题的: + +var YAxisPoint = Point.bind(null, 0/*x*/); + +/*(译注:polyfill 的 bind 方法中,如果把 bind 的第一个参数加上, +即对新绑定的 this 执行 Object(this),包装为对象, +因为 Object(null) 是 {},所以也可以支持)*/ + +var axisPoint = new YAxisPoint(5); +axisPoint.toString(); // '0,5' + +axisPoint instanceof Point; // true +axisPoint instanceof YAxisPoint; // true +new YAxisPoint(17, 42) instanceof Point; // true</pre> + +<p>请注意,你不需要做特别的处理就可以用 {{jsxref("Operators/new", "new")}} 操作符创建一个绑定函数。也就是说,你不需要做特别处理就可以创建一个可以被直接调用的绑定函数,即使你更希望绑定函数是用 {{jsxref("Operators/new", "new")}} 操作符来调用。</p> + +<pre class="brush: js notranslate">// ...接着上面的代码继续的话, +// 这个例子可以直接在你的 JavaScript 控制台运行 + +// 仍然能作为一个普通函数来调用 +// (即使通常来说这个不是被期望发生的) +YAxisPoint(13); + +emptyObj.x + ',' + emptyObj.y; // '0,13' +</pre> + +<p>如果你希望一个绑定函数要么只能用 {{jsxref("Operators/new", "new")}} 操作符,要么只能直接调用,那你必须在目标函数上显式规定这个限制。</p> + +<h3 id="快捷调用">快捷调用</h3> + +<p>在你想要为一个需要特定的 <strong><code>this</code></strong> 值的函数创建一个捷径(shortcut)的时候,<code>bind()</code> 也很好用。</p> + +<p>你可以用 {{jsxref("Array.prototype.slice")}} 来将一个类似于数组的对象(array-like object)转换成一个真正的数组,就拿它来举例子吧。你可以简单地这样写:</p> + +<pre class="brush: js notranslate">var slice = Array.prototype.slice; + +// ... + +slice.apply(arguments);</pre> + +<p>用 <code>bind()</code>可以使这个过程变得简单。在下面这段代码里面,<code>slice</code> 是 {{jsxref("Function.prototype")}} 的 {{jsxref("Function.prototype.apply()", "apply()")}} 方法的绑定函数,并且将 {{jsxref("Array.prototype")}} 的 {{jsxref("Array.prototype.slice()", "slice()")}} 方法作为 <strong><code>this</code></strong> 的值。这意味着我们压根儿用不着上面那个 <code>apply()</code>调用了。</p> + +<pre class="brush: js notranslate">// 与前一段代码的 "slice" 效果相同 +var unboundSlice = Array.prototype.slice; +var slice = Function.prototype.apply.bind(unboundSlice); + +// ... + +slice(arguments);</pre> + +<h2 id="Polyfill">Polyfill</h2> + +<p>有两种实现<code>bind</code>的方法,下面第一种不支持使用<code>new</code>调用新创建的构造函数,而第二种支持。</p> + +<pre class="brush: js line-numbers language-js notranslate"><code class="language-js"><span class="comment token">// Does not work with `new (funcA.bind(thisArg, args))`</span> +<span class="keyword token">if</span> <span class="punctuation token">(</span><span class="operator token">!</span><span class="class-name token">Function</span><span class="punctuation token">.</span>prototype<span class="punctuation token">.</span>bind<span class="punctuation token">)</span> <span class="punctuation token">(</span><span class="keyword token">function</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">{</span> + <span class="keyword token">var</span> slice <span class="operator token">=</span> <span class="class-name token">Array</span><span class="punctuation token">.</span>prototype<span class="punctuation token">.</span>slice<span class="punctuation token">;</span> + <span class="class-name token">Function</span><span class="punctuation token">.</span>prototype<span class="punctuation token">.</span><span class="function function-variable token">bind</span> <span class="operator token">=</span> <span class="keyword token">function</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">var</span> thatFunc <span class="operator token">=</span> <span class="keyword token">this</span><span class="punctuation token">,</span> thatArg <span class="operator token">=</span> arguments<span class="punctuation token">[</span><span class="number token">0</span><span class="punctuation token">]</span><span class="punctuation token">;</span> + <span class="keyword token">var</span> args <span class="operator token">=</span> <span class="function token">slice</span><span class="punctuation token">.</span><span class="function token">call</span><span class="punctuation token">(</span>arguments<span class="punctuation token">,</span> <span class="number token">1</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="keyword token">if</span> <span class="punctuation token">(</span><span class="keyword token">typeof</span> thatFunc <span class="operator token">!==</span> <span class="string token">'function'</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="comment token">// closest thing possible to the ECMAScript 5</span> + <span class="comment token">// internal IsCallable function</span> + <span class="keyword token">throw</span> <span class="keyword token">new</span> <span class="class-name token">TypeError</span><span class="punctuation token">(</span><span class="string token">'Function.prototype.bind - '</span> <span class="operator token">+</span> + <span class="string token">'what is trying to be bound is not callable'</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span> + <span class="keyword token">return</span> <span class="keyword token">function</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">{</span> + <span class="keyword token">var</span> funcArgs <span class="operator token">=</span> args<span class="punctuation token">.</span><span class="function token">concat</span><span class="punctuation token">(</span><span class="function token">slice</span><span class="punctuation token">.</span><span class="function token">call</span><span class="punctuation token">(</span>arguments<span class="punctuation token">)</span><span class="punctuation token">)</span> + <span class="keyword token">return</span> <span class="function token">thatFunc</span><span class="punctuation token">.</span><span class="function token">apply</span><span class="punctuation token">(</span>thatArg<span class="punctuation token">,</span> funcArgs<span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">;</span> +<span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre> + +<p>你可以将这段代码插入到你的脚本开头,从而使你的 <code>bind()</code> 在没有内置实现支持的环境中也可以部分地使用<code>bind</code>。</p> + +<pre class="brush: js notranslate">// Yes, it does work with `new (funcA.bind(thisArg, args))` +if (!Function.prototype.bind) (function(){ + var ArrayPrototypeSlice = Array.prototype.slice; + Function.prototype.bind = function(otherThis) { + if (typeof this !== 'function') { + // closest thing possible to the ECMAScript 5 + // internal IsCallable function + throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); + } + + var baseArgs= ArrayPrototypeSlice.call(arguments, 1), + baseArgsLength = baseArgs.length, + fToBind = this, + fNOP = function() {}, + fBound = function() { + baseArgs.length = baseArgsLength; // reset to default base arguments + baseArgs.push.apply(baseArgs, arguments); + return fToBind.apply( + fNOP.prototype.isPrototypeOf(this) ? this : otherThis, baseArgs + ); + }; + + if (this.prototype) { + // Function.prototype doesn't have a prototype property + fNOP.prototype = this.prototype; + } + fBound.prototype = new fNOP(); + + return fBound; + }; +})();</pre> + +<p>上述算法和实际的实现算法还有许多其他的不同 (尽管可能还有其他不同之处,但已经没有必要再多列举):</p> + +<ul> + <li>这部分实现依赖于 {{jsxref("Array.prototype.slice()")}}, {{jsxref("Array.prototype.concat()")}}, {{jsxref("Function.prototype.apply()")}} 这些原生方法。</li> + <li>这部分实现创建的函数并没有 {{jsxref("Function.caller", "caller")}} 以及会在 get,set 或者 deletion 上抛出 {{jsxref("Global_Objects/TypeError", "TypeError")}}错误的 arguments 属性这两个不可改变的“毒药” 。(假如环境支持{{jsxref("Object.defineProperty()")}}, 或者实现支持{{jsxref("Object.defineGetter", "__defineGetter__")}} 和 {{jsxref("Object.defineSetter", "__defineSetter__")}} 扩展)</li> + <li>这部分实现创建的函数有 <code>prototype</code> 属性。(正确的绑定函数没有)</li> + <li>这部分实现创建的绑定函数所有的 length 属性并不是同ECMA-262标准一致的:它创建的函数的 length 是0,而在实际的实现中根据目标函数的 length 和预先指定的参数个数可能会返回非零的 length。</li> +</ul> + +<p>如果你选择使用这部分实现,<strong>你不能依赖于那些与 ECMA-262, 5th edition 规定的行为偏离的例子。</strong>在 <code>bind()</code> 函数被广泛支持之前,某些情况下(或者为了兼容某些特定需求对其做一些特定修改后)可以选择用这个实现作为过渡。</p> + +<p>请访问 <a href="https://github.com/Raynos/function-bind">https://github.com/Raynos/function-bind</a> 以查找更完整的解决方案!</p> + +<h2 id="规范" style="margin-bottom: 20px; line-height: 30px; font-size: 2.14285714285714rem;">规范</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">规范</th> + <th scope="col">状态</th> + <th scope="col">备注</th> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-15.3.4.5', 'Function.prototype.bind')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td>初始定义。在 JavaScript 1.8.5 中实现。</td> + </tr> + <tr> + <td>{{SpecName('ES2015', '#sec-function.prototype.bind', 'Function.prototype.bind')}}</td> + <td>{{Spec2('ES2015')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-function.prototype.bind', 'Function.prototype.bind')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + + + +<p>{{Compat("javascript.builtins.Function.bind")}}</p> + +<h2 id="相关链接">相关链接</h2> + +<ul> + <li>{{jsxref("Function.prototype.apply()")}}</li> + <li>{{jsxref("Function.prototype.call()")}}</li> + <li>{{jsxref("Functions", "函数")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/global_objects/function/call/index.html b/files/zh-cn/web/javascript/reference/global_objects/function/call/index.html new file mode 100644 index 0000000000..5b9fc87b48 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/function/call/index.html @@ -0,0 +1,174 @@ +--- +title: Function.prototype.call() +slug: Web/JavaScript/Reference/Global_Objects/Function/call +tags: + - JavaScript + - 函数 + - 方法 +translation_of: Web/JavaScript/Reference/Global_Objects/Function/call +--- +<div>{{JSRef}}</div> + +<p><code><strong>call()</strong></code> 方法使用一个指定的 <code>this</code> 值和单独给出的一个或多个参数来调用一个函数。</p> + +<div class="note"><strong>注意:</strong>该方法的语法和作用与 {{jsxref("Function.apply", "apply()")}} 方法类似,只有一个区别,就是 <code>call()</code> 方法接受的是<strong>一个参数列表</strong>,而 <code>apply()</code> 方法接受的是<strong>一个包含多个参数的数组</strong>。</div> + +<div>{{EmbedInteractiveExample("pages/js/function-call.html")}}</div> + + + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox"><code><em>function</em>.call(<em>thisArg</em>, <em>arg1</em>, <em>arg2</em>, ...)</code></pre> + +<h3 id="参数">参数</h3> + +<dl> + <dt><code>thisArg</code></dt> + <dd>可选的。在 <em><code>function</code></em> 函数运行时使用的 <code>this</code> 值。请注意,<code>this</code>可能不是该方法看到的实际值:如果这个函数处于<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Strict_mode" title="如果你想改变你的代码,让其工作在具有限制性JavaScript环境中,请参阅转换成严格模式。">非严格模式</a>下,则指定为 <code>null</code> 或 <code>undefined</code> 时会自动替换为指向全局对象,原始值会被包装。</dd> + <dt><code>arg1, arg2, ...</code></dt> + <dd>指定的参数列表。</dd> +</dl> + +<h2 id="返回值">返回值</h2> + +<p>使用调用者提供的 <code>this</code> 值和参数调用该函数的返回值。若该方法没有返回值,则返回 <code>undefined</code>。</p> + +<h2 id="描述">描述</h2> + +<p><code>call()</code> 允许为不同的对象分配和调用属于一个对象的函数/方法。</p> + +<p><code>call()</code> 提供新的 <strong>this </strong>值给当前调用的函数/方法。你可以使用 <code>call</code> 来实现继承:写一个方法,然后让另外一个新的对象来继承它(而不是在新对象中再写一次这个方法)。</p> + +<h2 id="示例">示例</h2> + +<h3 id="使用_call_方法调用父构造函数">使用 <code>call</code> 方法调用父构造函数</h3> + +<p>在一个子构造函数中,你可以通过调用父构造函数的 <code>call</code> 方法来实现继承,类似于 <code>Java</code> 中的写法。下例中,使用 <code>Food</code> 和 <code>Toy </code>构造函数创建的对象实例都会拥有在 <code>Product</code> 构造函数中添加的 <code>name</code> 属性和 <code>price</code> 属性,但 <code>category</code> 属性是在各自的构造函数中定义的。</p> + +<pre class="brush: js">function Product(name, price) { + this.name = name; + this.price = price; +} + +function Food(name, price) { + Product.call(this, name, price); + this.category = 'food'; +} + +function Toy(name, price) { + Product.call(this, name, price); + this.category = 'toy'; +} + +var cheese = new Food('feta', 5); +var fun = new Toy('robot', 40); +</pre> + +<h3 id="使用_call_方法调用匿名函数">使用 <code>call</code> 方法调用匿名函数</h3> + +<p>在下例中的 <code>for</code> 循环体内,我们创建了一个匿名函数,然后通过调用该函数的 <code>call</code> 方法,将每个数组元素作为指定的 <code>this</code> 值执行了那个匿名函数。这个匿名函数的主要目的是给每个数组元素对象添加一个 <code>print</code> 方法,这个 <code>print</code> 方法可以打印出各元素在数组中的正确索引号。当然,这里不是必须得让数组元素作为 <code>this</code> 值传入那个匿名函数(普通参数就可以),目的是为了演示 <code>call</code> 的用法。</p> + +<pre class="brush: js">var animals = [ + { species: 'Lion', name: 'King' }, + { species: 'Whale', name: 'Fail' } +]; + +for (var i = 0; i < animals.length; i++) { + (function(i) { + this.print = function() { + console.log('#' + i + ' ' + this.species + + ': ' + this.name); + } + this.print(); + }).call(animals[i], i); +} +</pre> + +<h3 id="使用_call_方法调用函数并且指定上下文的_this">使用 <code>call</code> 方法调用函数并且指定上下文的 '<code>this</code>'</h3> + +<p>在下面的例子中,当调用 <code>greet</code> 方法的时候,该方法的<code>this</code>值会绑定到 <code>obj</code> 对象。</p> + +<pre class="brush: js">function greet() { + var reply = [this.animal, 'typically sleep between', this.sleepDuration].join(' '); + console.log(reply); +} + +var obj = { + animal: 'cats', sleepDuration: '12 and 16 hours' +}; + +greet.call(obj); // cats typically sleep between 12 and 16 hours +</pre> + +<h3 id="使用_call_方法调用函数并且不指定第一个参数(argument)" style="margin-bottom: 20px; line-height: 30px;">使用 <code><strong>call</strong></code> 方法调用函数并且不指定第一个参数(<code>argument</code>)</h3> + +<p>在下面的例子中,我们调用了 <code>display</code> 方法,但并没有传递它的第一个参数。如果没有传递第一个参数,<code>this</code> 的值将会被绑定为全局对象。</p> + +<pre class="brush: js">var sData = 'Wisen'; + +function display() { + console.log('sData value is %s ', this.sData); +} + +display.call(); // sData value is Wisen</pre> + +<div class="note"> +<p><strong>注意:</strong>在严格模式下,<code>this</code> 的值将会是 <code>undefined</code>。见下文。</p> +</div> + +<pre class="brush: js">'use strict'; + +var sData = 'Wisen'; + +function display() { + console.log('sData value is %s ', this.sData); +} + +display.call(); // Cannot read the property of 'sData' of undefined</pre> + +<h2 id="规范" style="margin-bottom: 20px; line-height: 30px;">规范</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">规范版本</th> + <th scope="col">状态</th> + <th scope="col">说明</th> + </tr> + <tr> + <td>{{SpecName('ES1')}}</td> + <td>{{Spec2('ES1')}}</td> + <td>初始定义。在 JavaScript 1.3 中实现。</td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-15.3.4.4', 'Function.prototype.call')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-function.prototype.call', 'Function.prototype.call')}}</td> + <td>{{Spec2('ES6')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-function.prototype.call', 'Function.prototype.call')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + + + +<p>{{Compat("javascript.builtins.Function.call")}}</p> + +<h2 id="See_also" name="See_also" style="margin-bottom: 20px; line-height: 30px;">相关链接</h2> + +<ul> + <li>{{jsxref("Function.prototype.bind()")}}</li> + <li>{{jsxref("Function.prototype.apply()")}}</li> + <li><a href="/zh-CN/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript">JavaScript 面向对象入门</a></li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/global_objects/function/caller/index.html b/files/zh-cn/web/javascript/reference/global_objects/function/caller/index.html new file mode 100644 index 0000000000..a850d41582 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/function/caller/index.html @@ -0,0 +1,69 @@ +--- +title: Function.caller +slug: Web/JavaScript/Reference/Global_Objects/Function/caller +translation_of: Web/JavaScript/Reference/Global_Objects/Function/caller +--- +<div>{{JSRef("Global_Objects", "Function")}} {{non-standard_header}}</div> + +<h2 id="Summary" name="Summary">概述</h2> + +<p>返回调用指定函数的函数.</p> + +<p>该属性不是ECMA-262第3版标准的一部分.不过, <a href="/zh-cn/SpiderMonkey" title="zh-cn/SpiderMonkey">SpiderMonkey</a> (Mozilla的JavaScript引擎) (查看{{ Bug("65683") }}), V8 (Chrome的JavaScript引擎) 和 JScript(IE的ECMAScript实现)都已经支持了它.</p> + +<h2 id="Description" name="Description">描述</h2> + +<p>如果一个函数<code>f</code>是在全局作用域内被调用的,则<code>f.caller为</code><code>null</code>,相反,如果一个函数是在另外一个函数作用域内被调用的,则<code>f.caller指向调用它的那个函数.</code></p> + +<p>该属性的常用形式<code>arguments.callee.caller</code>替代了被废弃的 <a href="/zh-cn/JavaScript/Reference/Functions_and_function_scope/arguments/caller" title="zh-cn/JavaScript/Reference/Functions_and_function_scope/arguments/caller">arguments.caller</a>.</p> + +<h3 id="Notes" name="Notes">备注</h3> + +<p>注意,在使用递归调用时, 你不能使用此属性来重现出调用栈.请考虑以下代码:</p> + +<pre class="brush: js">function f(n) { g(n-1) } +function g(n) { if(n>0) f(n); else stop() } +f(2) +</pre> + +<p>当<code>stop()函数被调用时,调用栈是这样的</code>:</p> + +<pre class="brush: js">f(2) -> g(1) -> f(1) -> g(0) -> stop() +</pre> + +<p>由于下面的表达式为 true(只保留函数最后一次被调用时的caller):</p> + +<pre class="brush: js">stop.caller === g && f.caller === g && g.caller === f +</pre> + +<p>所以如果你尝试在<code>stop()</code>函数中获取调用栈的话:</p> + +<pre class="brush: js">var f = stop; +var stack = "调用栈:"; +while (f) { + stack += "\n" + f.name; + f = f.caller; +} +</pre> + +<p>则上面的代码会进入一个死循环.</p> + +<p>有一个特殊属性 <code>__caller__</code>, 可以返回调用当前函数的函数的活动对象(可以用来重现出整个调用栈), 但由于安全原因的考虑,该属性已被删除.</p> + +<h2 id="Examples" name="Examples">例子</h2> + +<h3 id="Example:_Checking_the_value_of_a_function.27s_caller_property" name="Example:_Checking_the_value_of_a_function.27s_caller_property">例子: 检测一个函数的<code>caller</code>属性的值</h3> + +<p>下例用来得出一个函数是被谁调用的<code>.</code></p> + +<pre class="brush: js">function myFunc() { + if (myFunc.caller == null) { + return ("<span><span class="string">该函数在全局作用域内被调用</span></span>!"); + } else + return ("调用我的是函数是" + myFunc.caller); +} +</pre> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + +<p>Function.caller目前被所有主流浏览器支持: Firefox, Safari, Chrome, Opera 和 IE. <a class="external" href="http://dl.dropbox.com/u/534786/callertest.html" title="http://dl.dropbox.com/u/534786/callertest.html"><span style="text-decoration: underline;">查看检测结果</span></a>.</p> diff --git a/files/zh-cn/web/javascript/reference/global_objects/function/displayname/index.html b/files/zh-cn/web/javascript/reference/global_objects/function/displayname/index.html new file mode 100644 index 0000000000..abf8452f93 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/function/displayname/index.html @@ -0,0 +1,121 @@ +--- +title: Function.displayName +slug: Web/JavaScript/Reference/Global_Objects/Function/displayName +translation_of: Web/JavaScript/Reference/Global_Objects/Function/displayName +--- +<div>{{JSRef}} {{non-standard_header}}</div> + +<p><strong><code>function.displayName</code></strong> 属性获取函数的显示名称</p> + +<h2 id="Description_描述">Description 描述</h2> + +<p>当一个函数的 <code>displayName</code> 属性被定义,这个函数的 <code>displayName</code> 属性将返回显示名称。</p> + +<pre class="brush: js">function doSomething() {} + +console.log(doSomething.displayName); // "undefined" + +var popup = function(content) { console.log(content); }; + +popup.displayName = 'Show Popup'; + +console.log(popup.displayName); // "Show Popup" +</pre> + +<p>可以在函数表达式重定义函数的显示名称{{jsxref("Functions", "function expression", "", 1)}}:</p> + +<pre class="brush: js">var object = { + someMethod: function() {} +}; + +object.someMethod.displayName = 'someMethod'; + +console.log(object.someMethod.displayName); // logs "someMethod" + +try { someMethod } catch(e) { console.log(e); } +// ReferenceError: someMethod is not defined +</pre> + +<p>可以动态修改函数的显示名称:</p> + +<pre class="brush: js">var object = { + // anonymous + someMethod: function(value) { + arguments.callee.displayName = 'someMethod (' + value + ')'; + } +}; + +console.log(object.someMethod.displayName); // "undefined" + +object.someMethod('123') +console.log(object.someMethod.displayName); // "someMethod (123)" +</pre> + +<h2 id="Examples_例子">Examples 例子</h2> + +<p>这个显示名称通常在控制台和配置文件中,用它来提醒对它背后的真实函数名 {{jsxref("Function.name", "func.name")}}的引用。例如:</p> + +<p>通过如下的举例,显示的名称应该显示像"function My Function()"</p> + +<pre class="brush: js">var a = function() {}; +a.displayName = 'My Function'; + +a; // "function My Function()"</pre> + +<h2 id="Specifications_规范">Specifications 规范</h2> + +<p>不属于任何规范</p> + +<h2 id="Browser_compatibility_浏览器兼容性">Browser compatibility 浏览器兼容性</h2> + +<p>如果你愿意贡献数据,请访问<a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a>并同时给我们发送推送请求。</p> + +<div>{{CompatibilityTable}}</div> + +<div id="compat-desktop"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Chrome</th> + <th>Firefox (Gecko)</th> + <th>Internet Explorer</th> + <th>Opera</th> + <th>Safari</th> + </tr> + <tr> + <td>Basic support</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatGeckoDesktop(13)}}</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatUnknown}}</td> + </tr> + </tbody> +</table> +</div> + +<div id="compat-mobile"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Android</th> + <th>Chrome for Android</th> + <th>Firefox Mobile (Gecko)</th> + <th>IE Mobile</th> + <th>Opera Mobile</th> + <th>Safari Mobile</th> + </tr> + <tr> + <td>Basic support</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatUnknown}}</td> + </tr> + </tbody> +</table> +</div> diff --git a/files/zh-cn/web/javascript/reference/global_objects/function/index.html b/files/zh-cn/web/javascript/reference/global_objects/function/index.html new file mode 100644 index 0000000000..217ac78e3d --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/function/index.html @@ -0,0 +1,156 @@ +--- +title: Function +slug: Web/JavaScript/Reference/Global_Objects/Function +tags: + - Constructor + - Function + - JavaScript + - 函数 + - 构造器 +translation_of: Web/JavaScript/Reference/Global_Objects/Function +--- +<div>{{JSRef}}</div> + +<div>每个 JavaScript 函数实际上都是一个 <code>Function</code> 对象。运行 <code>(function(){}).constructor === Function // true</code> 便可以得到这个结论。</div> + +<h2 id="构造函数">构造函数</h2> + +<p><strong><code>Function</code> 构造函数</strong>创建一个新的 <code>Function</code> <strong>对象</strong>。直接调用此构造函数可用动态创建函数,但会遇到和 {{jsxref("eval")}} 类似的的安全问题和(相对较小的)性能问题。然而,与 <code>eval</code> 不同的是,<code>Function</code> 创建的函数只能在全局作用域中运行。</p> + +<div>{{EmbedInteractiveExample("pages/js/function-constructor.html")}}</div> + + + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox"><code>new Function ([<var>arg1</var>[, <var>arg2</var>[, ...<var>argN</var>]],] <var>functionBody</var>)</code></pre> + +<h3 id="参数">参数</h3> + +<dl> + <dt><code>arg1, arg2, ... arg<em>N</em></code></dt> + <dd>被函数使用的参数的名称必须是合法命名的。参数名称是一个有效的JavaScript标识符的字符串,或者一个用逗号分隔的有效字符串的列表;例如“<code>×</code>”,“<code>theValue</code>”,或“<code>a,b</code>”。</dd> + <dt><code>functionBody</code></dt> + <dd>一个含有包括函数定义的 JavaScript 语句的<strong>字符串</strong>。</dd> +</dl> + +<h2 id="描述">描述</h2> + +<p>使用 <code>Function</code> 构造器生成的 <code>Function</code> 对象是在函数创建时解析的。这比你使用<a href="/zh-CN/docs/Web/JavaScript/Reference/Operators/function">函数声明</a>或者<a href="/zh-CN/docs/Web/JavaScript/Reference/Operators/function">函数表达式</a>并在你的代码中调用更为低效,因为使用后者创建的函数是跟其他代码一起解析的。</p> + +<p>所有被传递到构造函数中的参数,都将被视为将被创建的函数的参数,并且是相同的标示符名称和传递顺序。<a href="/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/eval"><span style="display: none;"> </span></a></p> + +<p>以调用函数的方式调用 <code>Function</code> 的构造函数(而不是使用 <code>new</code> 关键字) 跟以构造函数来调用是一样的。</p> + +<h2 id="属性和方法">属性和方法</h2> + +<p>全局的 <code>Function</code> 对象没有自己的属性和方法,但是,因为它本身也是一个函数,所以它也会通过原型链从自己的原型链 {{jsxref("Function.prototype")}} 上继承一些属性和方法。</p> + +<h2 id="原型对象">原型对象</h2> + +<h3 id="属性">属性</h3> + +<div>{{page('/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/prototype', '属性')}}</div> + +<h3 id="方法">方法</h3> + +<div>{{page('/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/prototype', '方法')}}</div> + +<h2 id="实例">实例</h2> + +<p><code>Function</code> 实例从 {{jsxref("Function.prototype")}} 继承了一些属性和方法。 同其他构造函数一样, 你可以改变构造函数的原型从而使得所有的 <code>Function</code> 实例的属性和方法发生改变。</p> + +<h2 id="示例">示例</h2> + +<h3 id="传入参数调用_Function_构造函数">传入参数调用 Function 构造函数</h3> + +<p>下面的代码会创建一个需要两个参数的 <code>Function</code> 对象。</p> + +<pre class="brush: js">// 可以直接在 JavaScript 控制台中运行 + +// 创建了一个能返回两个参数和的函数 +const adder = new Function("a", "b", "return a + b"); + +// 调用函数 +adder(2, 6); +// > 8 +</pre> + +<p>参数 "<code>a</code>" 和 "<code>b</code>" 是参数的名字,在函数体中被使用,"<code>return a + b</code>"。</p> + +<h3 id="Function_构造器与函数声明之间的不同">Function 构造器与函数声明之间的不同</h3> + +<p>由 <code>Function</code> 构造器创建的函数不会创建当前环境的闭包,它们总是被创建于全局环境,因此在运行时它们只能访问全局变量和自己的局部变量,不能访问它们被 <code>Function</code> 构造器创建时所在的作用域的变量。这一点与使用 {{jsxref("eval")}} 执行创建函数的代码不同。</p> + +<pre class="brush: js">var x = 10; + +function createFunction1() { + var x = 20; + return new Function('return x;'); // 这里的 x 指向最上面全局作用域内的 x +} + +function createFunction2() { + var x = 20; + function f() { + return x; // 这里的 x 指向上方本地作用域内的 x + } + return f; +} + +var f1 = createFunction1(); +console.log(f1()); // 10 +var f2 = createFunction2(); +console.log(f2()); // 20 +</pre> + +<p>虽然这段代码可以在浏览器中正常运行,但在 Node.js 中 <code>f1()</code> 会产生一个“找不到变量 <code>x</code> ”的 <code>ReferenceError</code>。这是因为在 Node 中顶级作用域不是全局作用域,而 <code>x</code> 其实是在当前模块的作用域之中。</p> + +<h2 id="规范">规范</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('ES1')}}</td> + <td>{{Spec2('ES1')}}</td> + <td>Initial definition. Implemented in JavaScript 1.0.</td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-15.3', 'Function')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-function-objects', 'Function')}}</td> + <td>{{Spec2('ES6')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-function-objects', 'Function')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + + + +<p>{{Compat("javascript.builtins.Function")}}</p> + +<h2 id="相关链接">相关链接</h2> + +<ul> + <li>{{jsxref("Functions", "函数与函数作用域")}}</li> + <li>{{jsxref("Statements/function", "函数声明")}}</li> + <li>{{jsxref("Operators/function", "函数表达式")}}</li> + <li>{{jsxref("Statements/function*", "function* 声明")}}</li> + <li>{{jsxref("Operators/function*", "function* 表达式")}}</li> + <li>{{jsxref("AsyncFunction")}}</li> + <li>{{jsxref("GeneratorFunction")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/global_objects/function/isgenerator/index.html b/files/zh-cn/web/javascript/reference/global_objects/function/isgenerator/index.html new file mode 100644 index 0000000000..f377f0a210 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/function/isgenerator/index.html @@ -0,0 +1,40 @@ +--- +title: Function.prototype.isGenerator() +slug: Web/JavaScript/Reference/Global_Objects/Function/isGenerator +translation_of: Archive/Web/JavaScript/Function.isGenerator +--- +<div>{{JSRef("Global_Objects", "Function")}} {{non-standard_header}}</div> + +<h2 id="概述">概述</h2> + +<p>判断一个函数是否是一个<a href="/zh-cn/JavaScript/Guide/Iterators_and_Generators#Generators.3a_a_better_way_to_build_Iterators" title="zh-cn/Core JavaScript 1.5 Guide/Iterators and Generators#Generators.3a a better way to build Iterators">生成器</a>.</p> + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox"><code><var>fun</var>.isGenerator()</code></pre> + +<h2 id="描述">描述</h2> + +<p>该方法用来判断一个函数是否是一个<a href="/zh-cn/JavaScript/Guide/Iterators_and_Generators#Generators.3a_a_better_way_to_build_Iterators" title="zh-cn/Core JavaScript 1.5 Guide/Iterators and Generators#Generators.3a a better way to build Iterators">生成器</a>.</p> + +<h2 id="例子">例子</h2> + +<pre class="brush: js">function f() {} +function* g() { + yield 42; +} +console.log("f.isGenerator() = " + f.isGenerator()); +console.log("g.isGenerator() = " + g.isGenerator()); +</pre> + +<p>上面代码的输出结果为</p> + +<pre>f.isGenerator() = false +g.isGenerator() = true +</pre> + +<h2 id="相关链接">相关链接</h2> + +<ul> + <li><a href="/zh-cn/JavaScript/Guide/Iterators_and_Generators" title="zh-cn/Core JavaScript 1.5 Guide/Iterators and Generators">迭代器和生成器</a></li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/global_objects/function/length/index.html b/files/zh-cn/web/javascript/reference/global_objects/function/length/index.html new file mode 100644 index 0000000000..9804d07a75 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/function/length/index.html @@ -0,0 +1,89 @@ +--- +title: Function.length +slug: Web/JavaScript/Reference/Global_Objects/Function/length +tags: + - Function + - JavaScript + - Property +translation_of: Web/JavaScript/Reference/Global_Objects/Function/length +--- +<div>{{JSRef}}</div> + +<p><code><strong>length</strong></code> 属性指明函数的形参个数。</p> + +<p>{{EmbedInteractiveExample("pages/js/function-length.html")}}</p> + +<div>{{js_property_attributes(0,0,1)}}</div> + +<h2 id="Description" name="Description">描述</h2> + +<p><code>length</code> 是函数对象的一个属性值,指该函数有多少个必须要传入的参数,即形参的个数。</p> + +<p>形参的数量不包括剩余参数个数,仅包括第一个具有默认值之前的参数个数。</p> + +<p>与之对比的是, {{jsxref("Functions_and_function_scope/arguments/length", "arguments.length")}} 是函数被调用时实际传参的个数。</p> + +<h3 id="Function_构造器的属性"><code>Function</code> 构造器的属性</h3> + +<p>{{jsxref("Function")}} 构造器本身也是个<a href="/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function">Function</a>。他的 <code>length</code> 属性值为 1 。该属性 Writable: <code>false</code>, Enumerable: <code>false</code>, Configurable: <code>true</code>.</p> + +<h3 id="Function.prototype_对象的属性"><code>Function</code>.prototype 对象的属性</h3> + +<p> {{jsxref("Function.prototype")}} 对象的 length 属性值为 0 。</p> + +<h2 id="Examples" name="Examples">示例</h2> + +<pre class="brush: js">console.log(Function.length); /* 1 */ + +console.log((function() {}).length); /* 0 */ +console.log((function(a) {}).length); /* 1 */ +console.log((function(a, b) {}).length); /* 2 etc. */ + +console.log((function(...args) {}).length); +// 0, rest parameter is not counted + +console.log((function(a, b = 1, c) {}).length); +// 1, only parameters before the first one with +// a default value is counted</pre> + +<h2 id="规范">规范</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('ES1')}}</td> + <td>{{Spec2('ES1')}}</td> + <td>Initial definition. Implemented in JavaScript 1.1.</td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-15.3.5.1', 'Function.length')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-function-instances-length', 'Function.length')}}</td> + <td>{{Spec2('ES6')}}</td> + <td>The <code>configurable</code> attribute of this property is now <code>true</code>.</td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-function-instances-length', 'Function.length')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td> </td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容">浏览器兼容</h2> + +<div>{{Compat("javascript.builtins.Function.length")}}</div> + +<h2 id="参见">参见</h2> + +<ul> + <li>{{jsxref("Function")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/global_objects/function/name/index.html b/files/zh-cn/web/javascript/reference/global_objects/function/name/index.html new file mode 100644 index 0000000000..3c701acdca --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/function/name/index.html @@ -0,0 +1,219 @@ +--- +title: Function.name +slug: Web/JavaScript/Reference/Global_Objects/Function/name +tags: + - ECMAScript 2015 + - Function + - JavaScript + - Property +translation_of: Web/JavaScript/Reference/Global_Objects/Function/name +--- +<div>{{JSRef("Global_Objects", "Function")}}</div> + +<div><code><strong><em>function</em>.name</strong></code> 属性返回函数实例的名称。</div> + +<p>{{js_property_attributes(0,0,1)}}</p> + +<div class="note"> +<p>请注意,在非标准的ES2015之前的实现中,<code>configurable</code>属性也是<code>false</code> 。</p> +</div> + +<h2 id="示例">示例</h2> + +<h3 id="函数声明的名称">函数声明的名称</h3> + +<p> <code>name</code> 属性返回一个函数声明的名称。</p> + +<pre class="brush:js">function doSomething() { } +doSomething.name; // "doSomething" +</pre> + +<h3 id="构造函数的名称">构造函数的名称</h3> + +<p>使用<code>new Function(...)</code>语法创建的函数或只是 <code>Function(...) create</code> {{jsxref("Function")}}对象及其名称为“anonymous”。</p> + +<pre class="brush: js">(new Function).name; // "anonymous"</pre> + +<h3 id="推断函数名称">推断函数名称</h3> + +<p>变量和方法可以从句法位置推断匿名函数的名称(ECMAScript 2015中新增)。</p> + +<pre class="brush: js">var f = function() {}; +var object = { + someMethod: function() {} +}; + +console.log(f.name); // "f" +console.log(object.someMethod.name); // "someMethod"</pre> + +<p style="color: rgb(77, 78, 83);">你可以在 {{jsxref("Operators/Function", "函数表达式", "", 1)}}中定义函数的名称:</p> + +<pre class="brush:js">var object = { + someMethod: function object_someMethod() {} +}; + +console.log(object.someMethod.name); // "object_someMethod" + +try { object_someMethod } catch(e) { alert(e); } +// ReferenceError: object_someMethod is not defined +</pre> + +<p>你不能更改函数的名称,此属性是只读的:</p> + +<div class="hidden"> +<p>Example below contradicts with what is said at the beginning of this section and doesn't work as described.</p> +</div> + +<pre class="brush: js">var object = { + // anonymous + someMethod: function() {} +}; + +object.someMethod.name = 'otherMethod'; +console.log(object.someMethod.name); // someMethod</pre> + +<p>要更改它,可以使用{{jsxref("Object.defineProperty()")}}。</p> + +<h3 id="简写方法的名称">简写方法的名称</h3> + +<pre class="brush: js">var o = { + foo(){} +}; +o.foo.name; // "foo";</pre> + +<h3 id="绑定函数的名称">绑定函数的名称</h3> + +<p>{{jsxref("Function.bind()")}} 所创建的函数将会在函数的名称前加上"bound " 。</p> + +<pre class="brush: js">function foo() {}; +foo.bind({}).name; // "bound foo"</pre> + +<h3 id="getters_和_setters_的函数名">getters 和 setters 的函数名</h3> + +<p>当通过 <code><a href="/zh-CN/docs/Web/JavaScript/Reference/Functions/get">get</a></code> 和 <code><a href="/zh-CN/docs/Web/JavaScript/Reference/Functions/set">set</a></code> 访问器来存取属性时, "get" 或 "set" 会出现在函数名称前。</p> + +<pre class="brush: js">var o = { + get foo(){}, + set foo(x){} +}; + +var descriptor = Object.getOwnPropertyDescriptor(o, "foo"); +descriptor.get.name; // "get foo" +descriptor.set.name; // "set foo";</pre> + +<h3 id="类中的函数名称">类中的函数名称</h3> + +<p>你可以使用<code>obj.constructor.name</code>来检查对象的“类”(但请务必阅读以下警告):</p> + +<pre class="brush: js">function Foo() {} // ES2015 Syntax: class Foo {} + +var fooInstance = new Foo(); +console.log(fooInstance.constructor.name); // logs "Foo"</pre> + +<div class="warning"> +<p><strong>警告:</strong>脚本解释器只有在函数没有名为name的属性时才会设置内置的<code>Function.name</code>属性(参见 <a href="https://www.ecma-international.org/ecma-262/6.0/#sec-setfunctionname">9.2.11 of the ECMAScript2015 Language Specification</a>)。但是,ES2015规定由关键字<em>static</em>修饰的静态方法也会被认为是类的属性(ECMAScript2015, <a href="https://www.ecma-international.org/ecma-262/6.0/#sec-runtime-semantics-classdefinitionevaluation">14.5.14.21.b</a> + <a href="https://www.ecma-international.org/ecma-262/6.0/#sec-object-initializer-runtime-semantics-propertydefinitionevaluation">12.2.6.9</a>)。</p> +</div> + +<p>因此,我们无法获取具有静态方法属性<code>name()</code>的几乎任何类的类名称:</p> + +<pre class="brush: js">class Foo { + constructor() {} + static name() {} +} +</pre> + +<p>使用<code>static name()</code>方法<code>Foo.name</code>不再保存实际的类名称,而是引用<code>name()</code>函数对象。 ES2015语法中的上述类定义将在Chrome或Firefox中运行,类似于ES5语法中的以下代码段:</p> + +<pre class="brush: js">function Foo() {} +Object.defineProperty(Foo, 'name', { writable: true }); +Foo.name = function() {}; +</pre> + +<p>通过<code>fooInstance.constructor.name</code>获取<code>fooInstance</code>类不会给我们所有的类名,而是静态类方法的引用。 例如:</p> + +<pre class="brush: js">var fooInstance = new Foo(); +console.log(fooInstance.constructor.name); // logs function name()</pre> + +<p>你也可以从ES5语法示例中看到,在Chrome或Firefox的中静态定义的<code>Foo.name</code>变得可写。内置定义在没有自定义静态定义时是只读的:</p> + +<pre class="brush: js">Foo.name = 'Hello'; +console.log(Foo.name); +//如果Foo具有静态name()属性,则输出“Hello”,否则为“Foo” +</pre> + +<p>因此,你不能依赖内置的<code>Function.name</code>属性来保持一个类的名称。</p> + +<h3 id="Symbol作为函数名称">Symbol作为函数名称</h3> + +<p>如果{{jsxref("Symbol")}} 被用于函数名称,并且这个symbol具有相应的描述符,那么方法的名字就是方括号中的描述符。</p> + +<pre class="brush: js">var sym1 = Symbol("foo"); +var sym2 = Symbol(); +var o = { + [sym1]: function(){}, + [sym2]: function(){} +}; + +o[sym1].name; // "[foo]" +o[sym2].name; // "" +</pre> + +<h2 id="JavaScript_压缩和_minifiers">JavaScript 压缩和 minifiers</h2> + +<div class="warning"> +<p><strong>警告:</strong>当使用<code>Function.name</code>和那些JavaScript压缩器(minifiers)或混淆器进行源码转换时要小心。这些工具通常用作JavaScript构建管道的一部分,以在程序部署到生产之前减少程序的大小。但这种转换通常会在构建时更改函数的名称。</p> +</div> + +<p>例如下面的代码:</p> + +<pre class="brush: js">function Foo() {}; +var foo = new Foo(); + +if (foo.constructor.name === 'Foo') { + console.log("'foo' is an instance of 'Foo'"); +} else { + console.log('Oops!'); +}</pre> + +<p>可能被压缩为:</p> + +<pre class="brush: js">function a() {}; +var b = new a(); +if (b.constructor.name === 'Foo') { + console.log("'foo' is an instance of 'Foo'"); +} else { + console.log('Oops!'); +} +</pre> + +<p>在未压缩版本中,程序运行到真实分支并打印<code>'foo' is an instance of 'Foo'</code>。 而在压缩版本中,它的行为不同,并且进入else分支。如果您依赖于<code>Function.name</code>,就像上面的示例一样,确保您的构建管道不会更改函数名称,也不要假定函数具有特定的名称。</p> + +<article> +<h2 id="规范">规范</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('ES2015', '#sec-name', 'name')}}</td> + <td>{{Spec2('ES2015')}}</td> + <td>Initial definition.</td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-name', 'name')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td> </td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + +<div class="hidden">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.</div> + +<p>{{Compat("javascript.builtins.Function.name")}}</p> +</article> diff --git a/files/zh-cn/web/javascript/reference/global_objects/function/prototype/index.html b/files/zh-cn/web/javascript/reference/global_objects/function/prototype/index.html new file mode 100644 index 0000000000..afae311604 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/function/prototype/index.html @@ -0,0 +1,138 @@ +--- +title: Function.prototype +slug: Web/JavaScript/Reference/Global_Objects/Function/prototype +tags: + - JavaScript + - 函数 + - 原型 + - 原型属性 +translation_of: Web/JavaScript/Reference/Global_Objects/Function +--- +<div>{{JSRef}}</div> + +<p><code><strong>Function.prototype</strong></code> 属性存储了 {{jsxref("Function")}} 的原型对象。</p> + +<h2 id="Description" name="Description">描述</h2> + +<p>{{jsxref("Function")}}<code>对象继承自 Function.prototype 属性</code><code>。因此,Function.prototype</code> 不能被修改。</p> + +<h2 id="属性">属性</h2> + +<dl> + <dt>{{jsxref("Function.arguments")}} {{deprecated_inline()}}</dt> + <dd>以数组形式获取传入函数的所有参数。此属性已被{{jsxref("Functions_and_function_scope/arguments", "arguments")}}替代。</dd> + <dt><s class="obsoleteElement">{{jsxref("Function.arity")}} {{obsolete_inline() }}</s></dt> + <dd><s class="obsoleteElement">用于指定的函数的参数的个数,但已被删除。使用{{jsxref("Function.length","length")}}属性代替。</s></dd> + <dt>{{jsxref("Function.caller")}} {{ Non-standard_inline() }}</dt> + <dd>获取调用函数的具体对象。</dd> + <dt>{{jsxref("Function.length")}}</dt> + <dd>获取函数的接收参数个数。</dd> + <dt>{{jsxref("Function.name")}} {{ Non-standard_inline() }}</dt> + <dd>获取函数的名称。</dd> + <dt>{{jsxref("Function.displayName")}} {{ Non-standard_inline() }}</dt> + <dd>获取函数的display name。</dd> + <dt><code>Function.prototype.constructor</code></dt> + <dd>声明函数的原型构造方法,详细请参考 {{jsxref("Object.constructor")}} 。</dd> +</dl> + +<h2 id="方法">方法</h2> + +<dl> + <dt>{{jsxref("Function.prototype.apply()")}}</dt> + <dd>在一个对象的上下文中应用另一个对象的方法;参数能够以数组形式传入。</dd> + <dt>{{jsxref("Function.prototype.bind()")}}</dt> + <dd><span style="font-family: courier new,andale mono,monospace; line-height: 1.5;">bind()</span>方法会创建一个新函数,称为绑定函数.当调用这个绑定函数时,绑定函数会以创建它时传入 <span style="font-family: courier new,andale mono,monospace;">bind()</span>方法的第一个参数作为 <span style="font-family: courier new,andale mono,monospace;">this</span>,传入 <span style="font-family: courier new,andale mono,monospace;">bind()</span>方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数.</dd> + <dt>{{jsxref("Function.prototype.call()")}}</dt> + <dd>在一个对象的上下文中应用另一个对象的方法;参数能够以列表形式传入。</dd> + <dt>{{jsxref("Function.prototype.isGenerator()")}} {{ Non-standard_inline() }}</dt> + <dd><code>若函数对象为</code><a href="/zh-CN/docs/Web/JavaScript/Guide/Iterators_and_Generators">generator</a>,返回true,反之返回 <code>false</code>。</dd> + <dt>{{jsxref("Function.prototype.toSource()")}} {{ Non-standard_inline() }}</dt> + <dd>获取函数的实现源码的字符串。 覆盖了 {{jsxref("Object.prototype.toSource")}} 方法。</dd> + <dt>{{jsxref("Function.prototype.toString()")}}</dt> + <dd>获取函数的实现源码的字符串。覆盖了 {{jsxref("Object.prototype.toString")}} 方法。</dd> +</dl> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">规范</th> + <th scope="col">状态</th> + <th scope="col">说明</th> + </tr> + <tr> + <td>{{SpecName('ES1')}}</td> + <td>{{Spec2('ES1')}}</td> + <td>Initial definition.Implemented in JavaScript 1.1</td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-15.3.5.2', 'Function.prototype')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-function-instances-prototype', 'Function.prototype')}}</td> + <td>{{Spec2('ES6')}}</td> + <td> </td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + +<p>{{ CompatibilityTable() }}</p> + +<div id="compat-desktop"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Chrome</th> + <th>Firefox (Gecko)</th> + <th>Internet Explorer</th> + <th>Opera</th> + <th>Safari</th> + </tr> + <tr> + <td>Basic support</td> + <td>{{ CompatVersionUnknown() }}</td> + <td>{{ CompatVersionUnknown() }}</td> + <td>{{ CompatVersionUnknown() }}</td> + <td>{{ CompatVersionUnknown() }}</td> + <td>{{ CompatVersionUnknown() }}</td> + </tr> + </tbody> +</table> +</div> + +<div id="compat-mobile"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Android</th> + <th>Chrome for Android</th> + <th>Firefox Mobile (Gecko)</th> + <th>IE Mobile</th> + <th>Opera Mobile</th> + <th>Safari Mobile</th> + </tr> + <tr> + <td>Basic support</td> + <td>{{ CompatVersionUnknown() }}</td> + <td>{{ CompatVersionUnknown() }}</td> + <td>{{ CompatVersionUnknown() }}</td> + <td>{{ CompatVersionUnknown() }}</td> + <td>{{ CompatVersionUnknown() }}</td> + <td>{{ CompatVersionUnknown() }}</td> + </tr> + </tbody> +</table> +</div> + +<h2 id="参考">参考</h2> + +<ul> + <li>{{jsxref("Function")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/global_objects/function/tosource/index.html b/files/zh-cn/web/javascript/reference/global_objects/function/tosource/index.html new file mode 100644 index 0000000000..5c4de38138 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/function/tosource/index.html @@ -0,0 +1,49 @@ +--- +title: Function.prototype.toSource() +slug: Web/JavaScript/Reference/Global_Objects/Function/toSource +translation_of: Web/JavaScript/Reference/Global_Objects/Function/toSource +--- +<div> +<div>{{JSRef("Global_Objects", "Function")}} {{non-standard_header}}</div> +</div> + +<h2 id="Summary" name="Summary">概述</h2> + +<p>返回函数的源代码的字符串表示.</p> + +<h2 id="Syntax" name="Syntax">语法</h2> + +<pre class="syntaxbox"><code><var>function</var>.toSource(); +Function.toSource(); +</code></pre> + +<h3 id="Parameters" name="Parameters">参数</h3> + +<p>无</p> + +<h2 id="Description" name="Description">描述</h2> + +<p><code>toSource方法返回下面的值</code>:</p> + +<p></p> + +<ul> + <li>对于内置的<code>Function</code>对象,<code>toSource</code>返回下面的字符串:</li> +</ul> + +<pre class="brush: js"><code>function Function() { + [native code] +}</code></pre> + +<ul> + <li>对于自定义函数来说, <code>toSource返回能定义该函数</code>的Javascript源码.</li> +</ul> + +<p>该方法通常在引擎内部调用.你可以在调试的时候用该方法开查看一个函数的源代码.</p> + +<h2 id="See_Also" name="See_Also">相关链接</h2> + +<ul> + <li><a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Function/toString" title="JavaScript/Reference/Global_Objects/Function/toString">toString</a></li> + <li><a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Object/valueOf" title="JavaScript/Reference/Global_Objects/Object/valueOf">Object.prototype.valueOf</a></li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/global_objects/function/tostring/index.html b/files/zh-cn/web/javascript/reference/global_objects/function/tostring/index.html new file mode 100644 index 0000000000..01bf4d2ce7 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/function/tostring/index.html @@ -0,0 +1,230 @@ +--- +title: Function.prototype.toString() +slug: Web/JavaScript/Reference/Global_Objects/Function/toString +tags: + - Function + - JavaScript + - Method +translation_of: Web/JavaScript/Reference/Global_Objects/Function/toString +--- +<div>{{JSRef}}</div> + +<p><strong><code>toString()</code> </strong>方法返回一个表示当前函数源代码的字符串。</p> + +<div>{{EmbedInteractiveExample("pages/js/function-tostring.html")}}</div> + +<h2 id="Syntax" name="Syntax">语法</h2> + +<pre class="syntaxbox"><code><var>function</var>.toString()</code></pre> + +<h3 id="返回值">返回值</h3> + +<p>表示函数源代码的一个字符串</p> + +<h2 id="Description" name="Description">描述</h2> + +<p>{{jsxref("Function")}}对象覆盖了从{{jsxref("Object")}}继承来的{{jsxref("Object.prototype.toString", "toString")}} 方法。对于用户定义的 {{jsxref("Function")}} 对象,<code>toString</code>方法返回一个字符串,其中包含用于定义函数的源文本段。</p> + +<p>在{{jsxref("Function")}}需要转换为字符串时,通常会自动调用函数的 <code>toString </code>方法。</p> + +<p>若 <code>this</code> 不是 <code>Function </code>对象,则 <code>toString()</code> 方法将抛出 {{jsxref("TypeError")}} ("Function.prototype.toString called on incompatible object") 异常,比如 {{jsxref("Proxy")}} 对象就会抛出异常。</p> + +<pre class="brush: js example-bad">Function.prototype.toString.call('foo'); // TypeError +</pre> + +<p>如果是在内置函数或由 <code>Function.prototype.bind </code>返回的函数上调用 <code>toString()</code>,则<code>toString()</code> 返回原生代码字符串,如下</p> + +<pre class="brush: js">"function () {\n [native code]\n}" +</pre> + +<p>若是在由 <code>Function</code> 构造器生成的函数上调用 <code>toString()</code> ,则 <code>toString()</code> 返回创建后的函数源码,包括形参和函数体,函数名为 "anonymous"。</p> + +<h2 id="示例">示例</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Function</th> + <th scope="col">Function.prototype.toString result</th> + </tr> + </thead> + <tbody> + <tr> + <td> + <pre> +function f(){}</pre> + </td> + <td> + <pre> +"function f(){}"</pre> + </td> + </tr> + <tr> + <td> + <pre> +class A { a(){} }</pre> + </td> + <td> + <pre> +"class A { a(){} }"</pre> + </td> + </tr> + <tr> + <td> + <pre> +function* g(){}</pre> + </td> + <td> + <pre> +"function* g(){}"</pre> + </td> + </tr> + <tr> + <td> + <pre> +a => a</pre> + </td> + <td> + <pre> +"a => a"</pre> + </td> + </tr> + <tr> + <td> + <pre> +({ a(){} }.a)</pre> + </td> + <td> + <pre> +"a(){}"</pre> + </td> + </tr> + <tr> + <td> + <pre> +({ *a(){} }.a)</pre> + </td> + <td> + <pre> +"*a(){}"</pre> + </td> + </tr> + <tr> + <td> + <pre> +({ [0](){} }[0])</pre> + </td> + <td> + <pre> +"[0](){}"</pre> + </td> + </tr> + <tr> + <td> + <pre> +Object.getOwnPropertyDescriptor({ + get a(){} +}, "a").get</pre> + </td> + <td> + <pre> +"get a(){}"</pre> + </td> + </tr> + <tr> + <td> + <pre> +Object.getOwnPropertyDescriptor({ + set a(x){} +}, "a").set</pre> + </td> + <td> + <pre> +"set a(x){}"</pre> + </td> + </tr> + <tr> + <td> + <pre> +Function.prototype.toString</pre> + </td> + <td> + <pre> +"function toString() { [native code] }"</pre> + </td> + </tr> + <tr> + <td> + <pre> +(function f(){}.bind(0))</pre> + </td> + <td> + <pre> +"function () { [native code] }"</pre> + </td> + </tr> + <tr> + <td> + <pre> +Function("a", "b")</pre> + </td> + <td> + <pre> +"function anonymous(a\n) {\nb\n}"</pre> + </td> + </tr> + </tbody> +</table> + +<h2 id="规范" style="margin-bottom: 20px; line-height: 30px;">规范</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">规范版本</th> + <th scope="col">规范状态</th> + <th scope="col">注解</th> + </tr> + <tr> + <td>{{SpecName('ES1')}}</td> + <td>{{Spec2('ES1')}}</td> + <td>初始定义。在 JavaScript 1.1 中实现。</td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-function.prototype.tostring', 'Function.prototype.toString')}}</td> + <td>{{Spec2('ES6')}}</td> + <td>对字符串表示增加了更多的特定需求。</td> + </tr> + <tr> + <td><a href="http://tc39.github.io/Function-prototype-toString-revision/">Function.prototype.toString revision</a></td> + <td>Draft</td> + <td>对内置函数与行尾表示进行标准化。</td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-function.prototype.tostring', 'Function.prototype.toString')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td> </td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + +<div> + + +<p>{{Compat("javascript.builtins.Function.toString")}}</p> +</div> + +<h2 id="附注(针对Firefox)">附注(针对Firefox)</h2> + +<ul> + <li>从Firefox 17开始,<code>Function.prototype.toString()</code> 通过保存函数源码的方式来实现,而之前是通过反编译器反编译函数字节码的方式来实现。反编译器已经被移除,因此我们不再需要 <code>indentation</code> 参数。查看 {{bug("761723")}} 获得更多信息。</li> + <li>从Firefox 38开始,<code>Function.prototype.toString()</code> 会对 {{jsxref("Proxy")}} 对象抛出异常 ({{bug(1100936)}})。</li> +</ul> + +<h2 id="See_also" name="See_also">相关链接</h2> + +<ul> + <li>{{jsxref("Object.prototype.toString()")}}</li> +</ul> |