代码之家  ›  专栏  ›  技术社区  ›  T.J. Crowder

为什么“obj”。foo=function(){};`不将名称“foo”分配给函数?

  •  55
  • T.J. Crowder  · 技术社区  · 9 年前

    从ES2015(ES6)开始,函数具有专有名称(包括官方名称 name 属性),并且在创建函数时,除了明显的函数声明和命名函数表达式之外,还以多种方式分配名称,例如分配给变量(函数名称设置为变量名称)、分配给对象属性(函数名称设为属性名称)、分配到对象属性(功能名称设置为属性名称),甚至函数参数的默认值(函数名称设置为参数名称)。但是分配给现有对象上的属性(例如,不在对象初始值设定项中)不会将该属性的名称分配给函数。为什么不呢?肯定有一个 具体的 原因:不可取/不可能。那是什么?

    明确一点:我不是问如何解决这个问题。我想问的是,当有这么多其他情况(包括默认参数值)时,是什么阻止了这个看似显而易见的案例被处理呢是一定有很好的理由。

    请不要推测或理论化。 TC39有理由不包括它。我感兴趣的原因是什么。我经历了 TC39 meeting notes 但还没有找到。到目前为止,我发现的最接近的是艾伦·沃夫斯·布罗克 replying to Bergi 他说,由于“各种各样的反对意见”,没有达成一致意见,但遗憾的是,他没有说明这些反对意见是什么。

    细节:

    foo 到 compliant browser :

    // Requires a compliant browser
    
    // Assigning to a variable or constant...
    // ...whether in the initializer...
    {
        let foo = function() { };
        console.log("1:", foo.name); // "foo"
    }
    {
        const foo = function() { };
        console.log("2:", foo.name); // "foo"
    }
    // ...or later...
    {
        let foo;
        foo = function() { };
        console.log("3:", foo.name); // "foo"
    }
    // As an initializer for an object property
    {
        const obj = {
            foo: function() { }
        };
        console.log("4:", obj.foo.name); // "foo"
    }
    // Or as a method
    {
        const obj = {
            foo() { }
        };
        console.log("5:", obj.foo.name); // "foo"
    }
    // Even if it's a computed property name
    {
        let name = "f";
        const obj = {
            [name + "o" + "o"]() { }
        };
        console.log("6:", obj.foo.name); // "foo"
    }
    // As a default value for a parameter
    (function(foo = function() { }) {
        console.log("7:", foo.name); // "foo"
    })();
    // ...and a bunch of others

    但是,在对象初始值设定项之外分配给现有对象的属性不会:

    const obj = {};
    obj.foo = function() { };
    console.log("Nope:", obj.foo.name);

    据我所知,这是由 this section 该规范只显式设置函数名,如果 IsIdentifierRef 的 左手表情 it isn't 用于属性引用)。

    因此,从上面重申:为什么不呢?肯定有一个 具体的 原因:不可取/不可能。那是什么?

    3 回复  |  直到 9 年前
        1
  •  16
  •   T.J. Crowder    9 年前

    艾伦·沃夫斯·布罗克 replied on the es-discuss list 反对意见阻碍了TC39就 obj.foo = function() { } 形式:

    对于

    cache[getUserSecret(user)] = function() {};
    

    它将泄漏秘密用户信息作为name的值

    和

    obj[someSymbol] = function() {}
    

    它将泄漏符号值作为名称的值

    和

     table[n]=function() {}
    

    名称可能是一个数字字符串

    有一些反对意见(特别是最后一个,它非常弱;有许多其他方法可以自动为函数分配数字字符串名称),但这不是重点;问题是,这些就是提出的反对意见。

    他还补充说,需要IsPropertyReference操作(目前只有一个IsIdentifierRef)。。。

    …是一个运行时操作,新语义要求运行时确定名称值。这是所有额外的运行时工作,可能会减慢出现在循环中的函数闭包的创建。

    总之,显然在做出决定的时候,这些反对意见一直存在(现在也很可能存在),这就是为什么这个表单不会自动命名函数,而其他表单则会。

        2
  •  -1
  •   Gabriel    9 年前

    我读了艾伦·沃夫·布罗克的回答,他明确地谈到了可能的安全问题。我个人同意他的观点。

    还可能存在安全问题。name属性可能会通过函数对象泄漏最初分配给它的变量的名称。但是,在原始函数之外,没有人可以对局部变量名做太多。但泄漏的属性名称可能具有更大的功能。

    他所说的反对似乎与此有关。 如果TC39没有进一步解释它的决定,很难找到他们为什么这样离开它:)。

        3
  •  -2
  •   scraaappy    9 年前

    我不确定有什么具体原因。

    obj.foo = function (){};
    

    首先在obj中创建函数表达式的引用, 然后将foo绑定到这个已经有(只读)名称的引用。

    因此:

    obj.fooC = (new Function ());
    console.log(obj.fooC.name);//'anonymous'
    
    obj.fooFE = function (){};
    console.log(obj.fooFE.name);//''
    
    obj.fooNFE = function a_name (){};
    console.log(obj.fooNFE.name);//'a_name'
    

    是正常行为。

    是否有写的限制:

    obj.foo = (function foo(){});
    
    推荐文章