美文网首页JavaScript
[ES] 函数的name属性

[ES] 函数的name属性

作者: 何幻 | 来源:发表于2018-01-05 19:27 被阅读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

    相关文章

      网友评论

        本文标题:[ES] 函数的name属性

        本文链接:https://www.haomeiwen.com/subject/tnjsnxtx.html