一、背景
ECMAScript使用SetFunctionName
,给函数添加name
属性。
SetFunctionName(F,name[,prefix])
- Assert:
F
is an extensible object that does not have aname
own property.- Assert:
Type(name)
is either Symbol or String.- Assert: If
prefix
was passed, thenType(prefix)
is String.- If
Type(name)
is Symbol, then
a. Letdescription
bename
's[[Description]]
value.
b. Ifdescription
isundefined
, setname
to the empty String.
c. Else, setname
to the concatenation of "[",description
, and "]".- If
prefix
was passed, then
a. Setname
to the concatenation ofprefix
, code unit0x0020
(SPACE), andname
.- Return ! DefinePropertyOrThrow(F, "name", PropertyDescriptor{[[Value]]: name, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true}).
注:
(1)传入SetFunctionName
的name
可以是字符串或者Symbol,
const k = Symbol.for('x');
const obj = {
[k](){ }
};
obj[k].name // "[x]"
(2)name
属性默认是只读的,但它是Configurable
的,
因此,可以通过defineProperty
修改为可写属性。
const f = function(){ };
f.name = 1;
f.name // f
Object.defineProperty(f, 'name', {
writable: true
});
f.name = 1;
f.name // 1
二、所有细节
*1. 属性定义
PropertyDefinition := PropertyName : AssignmentExpression
如果属性值是一个匿名函数,则将当前正在定义的属性名,设置为匿名函数的name
属性。
*2. 赋值
AssignmentExpression := LeftHandSideExpression = AssignmentExpression
如果赋值语句右侧为匿名函数,则将左侧变量的名字,设置为匿名函数的name
属性。
3. 解构
*(1)对象解构
AssignmentProperty := IdentifierReference Initializer
在进行对象解构操作时,如果解构变量的默认值为一个匿名函数,则将解构出来的变量名,设置为匿名函数的name
属性。
*(2)数组解构
a) AssignmentElement := DestructuringAssignmentTarget Initializer
b) AssignmentElement := DestructuringAssignmentTarget Initializer
在进行数组解构操作时,如果解构变量的默认值为一个匿名函数,则将解构出来的变量名,设置为匿名函数的name
属性。
*4. 变量定义
(1)LexicalBinding := BindingIdentifier Initializer
(2)VariableDeclaration := BindingIdentifier Initializer
(3)SingleNameBinding := BindingIdentifier Initializer
变量定义的时候,如果变量值是一个匿名函数,则将变量名设置为匿名函数的name
属性。
5. 函数
(1)具名函数声明
FunctionDeclaration := function BindingIdentifier ( FormalParameters ) { FunctionBody }
如果声明的函数有名字,那么就将该名字设置为函数的name
属性。
*(2)匿名函数声明
FunctionDeclaration := function ( FormalParameters ) { FunctionBody }
匿名函数声明只能出现在export default
后面,此时将"default"设置为匿名函数的name
属性。
(3)具名函数表达式
FunctionExpression := function BindingIdentifier ( FormalParameters ) { FunctionBody }
函数表达式定义的函数名,就是函数的name
属性。
6. 方法
(1)方法定义
MethodDefinition := PropertyName ( UniqueFormalParameters ) { FunctionBody }
对象的方法名,就是该方法的name
属性。
*(2)get方法定义
MethodDefinition := get PropertyName ( ) { FunctionBody }
对象get方法的name
属性,为"get"+" "+方法名。(传入SetFunctionName
的prefix
参数为"get")
*(3)set方法定义
MethodDefinition := set PropertyName ( PropertySetParameterList ) { FunctionBody }
对象set方法的name
属性,为"set"+" "+方法名。(传入SetFunctionName
的prefix
参数为"set")
const obj = {
get x(){ },
set y(i){ }
};
Object.getOwnPropertyDescriptor(obj,'x').set.name // "set x"
Object.getOwnPropertyDescriptor(obj,'x').get.name // "get y"
7. generator
(1)generator声明
GeneratorDeclaration := function * BindingIdentifier ( FormalParameters ) { GeneratorBody }
如果声明的generator函数有名字,那么就将该名字设置为generator函数的name
属性。
*(2)匿名generator声明
GeneratorDeclaration := function * ( FormalParameters ) { GeneratorBody }
匿名generator函数声明只能出现在export default
后面,此时将"default"设置为匿名generator函数的name
属性。
(3)generator方法
GeneratorMethod := * PropertyName ( UniqueFormalParameters ) { GeneratorBody }
对象generator方法名,就是generator函数的name
属性。
(4)具名generator表达式
GeneratorExpression := function * BindingIdentifier ( FormalParameters ) { GeneratorBody }
generator表达式定义的generator函数名,就是generator函数的name
属性。
8. class
*(1)class声明
ClassDeclaration := class BindingIdentifier ClassTail
class声明时的名字,就是class的name
属性。
*(2)具名class表达式
ClassExpression := class BindingIdentifier ClassTail
具名class表达式定义的名字,就是class的name
属性。
注:
class的静态name
方法,不会被class的名字覆盖。
class a {
static name(){ }
}
a.name // ƒ name(){ }
9. async函数
(1)async函数声明
AsyncFunctionDeclaration := async function BindingIdentifier ( FormalParameters ) { AsyncFunctionBody }
如果声明的async函数有名字,那么就将该名字设置为async函数的name
属性。
*(2)async匿名函数声明
AsyncFunctionDeclaration:async function ( FormalParameters ) { AsyncFunctionBody }
匿名async函数声明只能出现在export default
后面,此时将"default"设置为匿名async函数的name
属性。
(3)async方法
AsyncMethod := async PropertyName ( UniqueFormalParameters ) { AsyncFunctionBody }
对象async方法名,就是async函数的name
属性。
(4)async表达式
AsyncFunctionExpression := async functionBindingIdentifier ( FormalParameters ) { AsyncFunctionBody }
async表达式定义的async函数名,就是async函数的name
属性。
10. 模块
*(1)模块导出class声明
ExportDeclaration := export default ClassDeclaration
如果模块使用默认方式export default
导出class声明,则将"default"设置为class的name
属性。
*(2)模块导出表达式
ExportDeclaration := export default AssignmentExpression ;
如果模块使用默认方式export default
导出匿名函数表达式,则将"default"设置为函数的name
属性。
*11. 动态创建的函数
CreateDynamicFunction( constructor, newTarget, kind, args )
使用Function
动态创建的函数,将"anonymous"设置为函数的name
属性。
*12. bind返回的函数
Function.prototype.bind ( thisArg, ...args )
bind
返回函数的name
属性,为"bind"+" "+原函数名。(传入SetFunctionName
的prefix
参数为"bind")
const f = function(){ };
const g = f.bind(null);
g.name // "bind f"
参考
ECMAScript 2017 Language Specification
9.2.11 SetFunctionName