为什么`obj.foo = function(){};`不将名称`foo`赋给函数?

时间:2016-12-12 18:51:11

标签: javascript function ecmascript-6

从ES2015(ES6)开始,函数具有正确的名称(包括官方的name属性),除了明显的函数声明和命名函数之外,还以各种方式创建函数时分配名称表达式,例如赋值给变量(函数的名称设置为变量的名称),赋值给对象属性(函数的名称设置为属性的名称),甚至函数参数的默认值(函数的名称设置为参数的名称)。但是,在现有对象上(例如,不在对象初始值设定项中)分配属性不会将该属性的名称分配给该函数。为什么不?当然必须存在特定的原因,这是不可取/不可能的。它是什么?

要明确:我不是在问如何解决它。我问是什么阻止了这个看似显而易见的案例在被许多其他人(包括默认参数值!)处理时被处理。必须有充分的理由。

请不要推测或理论化。 TC39有理由不包括它。我对这个原因感兴趣。我已经通过了TC39 meeting notes,但还没有找到它。到目前为止,我发现的最接近的是艾伦·威尔夫斯·布洛克replying to Bergi,因为“各种异议”而没有达成共识,但遗憾的是他没有说出这些异议是什么。 / p>

详细说明:

以下所有内容都将名称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涵盖,如果 LeftHandSideExpression IsIdentifierRef ,它只显式设置函数名称是真的(显然it isn't用于属性引用)。

从上面重申:为什么不呢?当然必须存在特定的原因,这是不可取/不可能的。它是什么?

3 个答案:

答案 0 :(得分:14)

Allen Wirfs-Brock replied on the es-discuss list的反对意见阻止了TC39在obj.foo = function() { }形式上的共识:

  

... for

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

它会将秘密用户信息泄露为名称

的值      

obj[someSymbol] = function() {}
     

它会将Symbol值作为name

的值泄漏      

 table[n]=function() {}
     

名称可能是数字字符串

这些反对意见有一些反对意见(尤其是最后一个反对意见;还有许多其他方法可以自动为函数分配一个数字字符串名称),但这不是重点;关键是那些是提出的异议。

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

  

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

总而言之,显然在做出决定的时候,那些反对意见在当天进行(现在也很可能),这就是为什么这种形式不能自动命名功能而其他许多人做

答案 1 :(得分:-2)

我阅读了Allen Wirfs-Brock的答案,并明确谈到了可能存在的安全问题。我个人同意他的看法。

  

也可能存在安全问题。 name属性可能通过函数对象泄漏最初分配给它的变量的名称。但是,在原始函数之外,没有人可以使用局部变量名。但泄露的财产名称可能具有更大的能力。

他所谈论的反对意见似乎与它有关。 如果TC39没有进一步解释它的决定,那就很难找出他们为什么这样做了:)。

对不起,我无法帮助你。

答案 2 :(得分:-2)

我不确定是否有具体原因。

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(){});