aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/web/javascript/reference/global_objects/function/name/index.html
blob: 80253d1caadaf06f8a27b0fcff31e840765de419 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
---
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>

<p>{{Compat("javascript.builtins.Function.name")}}</p>
</article>