一准验、背景
ECMAScript使用SetFunctionName
,給函數(shù)添加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
屬性默認(rèn)是只讀的肢娘,但它是Configurable
的,
因此塌碌,可以通過defineProperty
修改為可寫屬性渊胸。
const f = function(){ };
f.name = 1;
f.name // f
Object.defineProperty(f, 'name', {
writable: true
});
f.name = 1;
f.name // 1
二、所有細(xì)節(jié)
*1. 屬性定義
PropertyDefinition := PropertyName : AssignmentExpression
如果屬性值是一個(gè)匿名函數(shù)誊爹,則將當(dāng)前正在定義的屬性名蹬刷,設(shè)置為匿名函數(shù)的name
屬性。
*2. 賦值
AssignmentExpression := LeftHandSideExpression = AssignmentExpression
如果賦值語句右側(cè)為匿名函數(shù)频丘,則將左側(cè)變量的名字办成,設(shè)置為匿名函數(shù)的name
屬性。
3. 解構(gòu)
*(1)對(duì)象解構(gòu)
AssignmentProperty := IdentifierReference Initializer
在進(jìn)行對(duì)象解構(gòu)操作時(shí)搂漠,如果解構(gòu)變量的默認(rèn)值為一個(gè)匿名函數(shù)迂卢,則將解構(gòu)出來的變量名,設(shè)置為匿名函數(shù)的name
屬性桐汤。
*(2)數(shù)組解構(gòu)
a) AssignmentElement := DestructuringAssignmentTarget Initializer
b) AssignmentElement := DestructuringAssignmentTarget Initializer
在進(jìn)行數(shù)組解構(gòu)操作時(shí)而克,如果解構(gòu)變量的默認(rèn)值為一個(gè)匿名函數(shù),則將解構(gòu)出來的變量名怔毛,設(shè)置為匿名函數(shù)的name
屬性员萍。
*4. 變量定義
(1)LexicalBinding := BindingIdentifier Initializer
(2)VariableDeclaration := BindingIdentifier Initializer
(3)SingleNameBinding := BindingIdentifier Initializer
變量定義的時(shí)候,如果變量值是一個(gè)匿名函數(shù)拣度,則將變量名設(shè)置為匿名函數(shù)的name
屬性碎绎。
5. 函數(shù)
(1)具名函數(shù)聲明
FunctionDeclaration := function BindingIdentifier ( FormalParameters ) { FunctionBody }
如果聲明的函數(shù)有名字螃壤,那么就將該名字設(shè)置為函數(shù)的name
屬性。
*(2)匿名函數(shù)聲明
FunctionDeclaration := function ( FormalParameters ) { FunctionBody }
匿名函數(shù)聲明只能出現(xiàn)在export default
后面筋帖,此時(shí)將"default"設(shè)置為匿名函數(shù)的name
屬性奸晴。
(3)具名函數(shù)表達(dá)式
FunctionExpression := function BindingIdentifier ( FormalParameters ) { FunctionBody }
函數(shù)表達(dá)式定義的函數(shù)名,就是函數(shù)的name
屬性日麸。
6. 方法
(1)方法定義
MethodDefinition := PropertyName ( UniqueFormalParameters ) { FunctionBody }
對(duì)象的方法名寄啼,就是該方法的name
屬性。
*(2)get方法定義
MethodDefinition := get PropertyName ( ) { FunctionBody }
對(duì)象get方法的name
屬性代箭,為"get"+" "+方法名墩划。(傳入SetFunctionName
的prefix
參數(shù)為"get")
*(3)set方法定義
MethodDefinition := set PropertyName ( PropertySetParameterList ) { FunctionBody }
對(duì)象set方法的name
屬性,為"set"+" "+方法名梢卸。(傳入SetFunctionName
的prefix
參數(shù)為"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函數(shù)有名字走诞,那么就將該名字設(shè)置為generator函數(shù)的name
屬性。
*(2)匿名generator聲明
GeneratorDeclaration := function * ( FormalParameters ) { GeneratorBody }
匿名generator函數(shù)聲明只能出現(xiàn)在export default
后面蛤高,此時(shí)將"default"設(shè)置為匿名generator函數(shù)的name
屬性蚣旱。
(3)generator方法
GeneratorMethod := * PropertyName ( UniqueFormalParameters ) { GeneratorBody }
對(duì)象generator方法名,就是generator函數(shù)的name
屬性戴陡。
(4)具名generator表達(dá)式
GeneratorExpression := function * BindingIdentifier ( FormalParameters ) { GeneratorBody }
generator表達(dá)式定義的generator函數(shù)名塞绿,就是generator函數(shù)的name
屬性。
8. class
*(1)class聲明
ClassDeclaration := class BindingIdentifier ClassTail
class聲明時(shí)的名字恤批,就是class的name
屬性异吻。
*(2)具名class表達(dá)式
ClassExpression := class BindingIdentifier ClassTail
具名class表達(dá)式定義的名字,就是class的name
屬性喜庞。
注:
class的靜態(tài)name
方法诀浪,不會(huì)被class的名字覆蓋。
class a {
static name(){ }
}
a.name // ? name(){ }
9. async函數(shù)
(1)async函數(shù)聲明
AsyncFunctionDeclaration := async function BindingIdentifier ( FormalParameters ) { AsyncFunctionBody }
如果聲明的async函數(shù)有名字延都,那么就將該名字設(shè)置為async函數(shù)的name
屬性雷猪。
*(2)async匿名函數(shù)聲明
AsyncFunctionDeclaration:async function ( FormalParameters ) { AsyncFunctionBody }
匿名async函數(shù)聲明只能出現(xiàn)在export default
后面,此時(shí)將"default"設(shè)置為匿名async函數(shù)的name
屬性晰房。
(3)async方法
AsyncMethod := async PropertyName ( UniqueFormalParameters ) { AsyncFunctionBody }
對(duì)象async方法名求摇,就是async函數(shù)的name
屬性。
(4)async表達(dá)式
AsyncFunctionExpression := async functionBindingIdentifier ( FormalParameters ) { AsyncFunctionBody }
async表達(dá)式定義的async函數(shù)名殊者,就是async函數(shù)的name
屬性与境。
10. 模塊
*(1)模塊導(dǎo)出class聲明
ExportDeclaration := export default ClassDeclaration
如果模塊使用默認(rèn)方式export default
導(dǎo)出class聲明,則將"default"設(shè)置為class的name
屬性猖吴。
*(2)模塊導(dǎo)出表達(dá)式
ExportDeclaration := export default AssignmentExpression ;
如果模塊使用默認(rèn)方式export default
導(dǎo)出匿名函數(shù)表達(dá)式摔刁,則將"default"設(shè)置為函數(shù)的name
屬性。
*11. 動(dòng)態(tài)創(chuàng)建的函數(shù)
CreateDynamicFunction( constructor, newTarget, kind, args )
使用Function
動(dòng)態(tài)創(chuàng)建的函數(shù)海蔽,將"anonymous"設(shè)置為函數(shù)的name
屬性簸搞。
*12. bind返回的函數(shù)
Function.prototype.bind ( thisArg, ...args )
bind
返回函數(shù)的name
屬性扁位,為"bind"+" "+原函數(shù)名。(傳入SetFunctionName
的prefix
參數(shù)為"bind")
const f = function(){ };
const g = f.bind(null);
g.name // "bind f"
參考
ECMAScript 2017 Language Specification
9.2.11 SetFunctionName