为什么`obj.foo = function(){};`不给函数赋“foo”这个名字?

从ES2015(ES6)开始,函数具有正确的名称(包括正式name属性),除了明显的函数声明和已命名的函数expression式(如赋值给variables(函数名称设置为variables的名称),赋值给对象属性(函数名称设置为属性名称),甚至函数参数(函数名称设置为参数名称)的默认值。 但是,分配给现有对象的属性(例如,不在对象初始值设定项中)不会将该属性的名称分配给该函数。 为什么不? 当然,一定有一个特定的原因是不可取的。 它以前如何?

要明确:我不是问如何解决这个问题。 我问的是什么阻止了这个看似明显的情况下被处理的时候,还有很多其他的(包括默认参数值!)。 一定有一个很好的理由。

请不要推测或理论。 TC39有理由不包括在内。 我对这个原因感兴趣。 我已经通过TC39会议笔记,但还没有find它。 我迄今发现的最接近的是艾伦· 维尔夫斯 ·布洛克(Allen Wirfs-Brock) 回答贝吉(Bergi)说,由于“各种各样的反对意见”,没有就这种forms达成共识。但遗憾的是,他没有说出那些反对意见是什么。

细节:

以下所有将名称foo分配给兼容浏览器上的function:

 // 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); 

据我所知,这部分规范涵盖了这一点 ,如果LeftHandSideExpressionIsIdentifierRef为true(显然它不是属性引用),它明确地只设置函数名。

所以从上面重申:为什么不呢? 当然,一定有一个特定的原因是不可取的。 它以前如何?

艾伦·维尔夫斯·布洛克(Allen Wirfs-Brock) 在讨论清单上回答了阻止TC39就obj.foo = function() { }forms达成共识的反对意见:

…对于

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

它会泄漏秘密用户信息作为名称的值

 obj[someSymbol] = function() {} 

它会泄漏Symbol值作为名称的值

  table[n]=function() {} 

名字可能是一个数字string

有些反对意见(特别是最后一个,这是非常薄弱的​​;还有很多其他的方式,一个函数自动分配一个数字string名称),但这不是重点; 关键是那些是提出的反对意见。

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

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

因此,总而言之,显然在做出决定的时候,这些反对意见是在当天进行的(现在很可能也是如此),这就是为什么这个表格不会自动命名function,而是有很多其他的function。

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

也可能有安全问题。 name属性可能会通过函数对象泄露最初分配给它的variables的名称。 但是在原始函数之外没有太多的人可以用局部variables名来做。 但泄漏的属性名称可能具有更大的能力。

看来他所说的反对意见跟它有关系。 如果TC39没有进一步解释这个决定的话,我们很难发现他们为什么要这么做:)。

对不起,我不能帮你进一步。

有一个名字的函数的想法是有点奇怪。 如果您将函数视为另一种variables,则分配它不应该更改分配的variables的内部状态。 这有点像魔术。 如果函数被传递的话,这会变得更加混乱(尽pipe可以通过在创build函数时仅分配名称来解决,而不是在传递函数时才能解决)。

我看起来好像有一个组织完全憎恨function名称的概念,还有另一个组织喜欢它们。 他们妥协,只为对象初始值设定项创build它们。

我个人同意那个认为function名称很奇怪的小组,但我也认为一旦你这样做,你应该一路走下去。 但是人类是这样愚蠢的。 妥协并不总是最有意义的。

我不确定是否有特定的原因。

 obj.foo = function (){}; 

首先为obj中的函数expression式创build一个引用,然后将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(){});