JavaScript

[ES] 函数的name属性

2018-01-05  本文已影响29人  何幻

一、背景

ECMAScript使用SetFunctionName,给函数添加name属性。

SetFunctionName(F,name[,prefix])

  1. Assert: F is an extensible object that does not have a name own property.
  2. Assert: Type(name) is either Symbol or String.
  3. Assert: If prefix was passed, then Type(prefix) is String.
  4. If Type(name) is Symbol, then
    a. Let description be name's [[Description]] value.
    b. If description is undefined, set name to the empty String.
    c. Else, set name to the concatenation of "[", description, and "]".
  5. If prefix was passed, then
    a. Set name to the concatenation of prefix, code unit 0x0020 (SPACE), and name.
  6. Return ! DefinePropertyOrThrow(F, "name", PropertyDescriptor{[[Value]]: name, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true}).

注:
(1)传入SetFunctionNamename可以是字符串或者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"+" "+方法名。(传入SetFunctionNameprefix参数为"get")

*(3)set方法定义
MethodDefinition := set PropertyName ( PropertySetParameterList ) { FunctionBody }
对象set方法的name属性,为"set"+" "+方法名。(传入SetFunctionNameprefix参数为"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"+" "+原函数名。(传入SetFunctionNameprefix参数为"bind")

const f = function(){ };
const g = f.bind(null);

g.name    // "bind f"

参考

ECMAScript 2017 Language Specification
9.2.11 SetFunctionName

上一篇下一篇

猜你喜欢

热点阅读