为啥 `obj.foo = function() ;` 没有将名称 `foo` 分配给函数?

Posted

技术标签:

【中文标题】为啥 `obj.foo = function() ;` 没有将名称 `foo` 分配给函数?【英文标题】:Why does `obj.foo = function() ;` not assign the name `foo` to the function?为什么 `obj.foo = function() ;` 没有将名称 `foo` 分配给函数? 【发布时间】:2017-04-27 17:08:23 【问题描述】:

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

要明确:我不是在问如何解决它。我在问,当有这么多其他情况(包括默认参数值!)时,是什么阻止了这种看似显而易见的情况的处理。一定有充分的理由。

请不要推测或理论化。 TC39 不包括它是有原因的。我对那个原因很感兴趣。我已经通过TC39 meeting notes 但还没有找到它。到目前为止我发现的最接近的是 Allen Wirfs-Brock 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 涵盖了这一点,该规范仅在 LeftHandSideExpressionIsIdentifierRef 为 true 时明确设置函数名称(显然it isn't 用于属性参考)。

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

【问题讨论】:

I asked this at esdiscuss,但没有提及原因。 @Bergi:谢谢。怎么……不满意。不幸的是,AWB 从未向您回复“各种反对意见”。 :-( 应该为obj.prop1 = obj.prop2 = function() 分配哪个名称?不分配任何东西是避免回答此类有争议的问题的一种非常方便的方法。 现在,对于var x = y = function() ...,我看到的第一个名字是var x,所以函数被命名为y这一事实可以说是令人困惑的并且可能被认为是一个错误。我认为在创建函数时分配名称的正确方法是使用明确的命名函数语法:var x = y = function y() @artem:这很有意义,并且与语言的工作方式完全一致。 x = y = function() ; 被评估为y = function() (创建函数,并为其命名,分配给y),然后将结果值(现有函数引用)分配给x .做任何其他事情都会违反标准的表达式语义,并且需要规范中极其复杂的机制来实现。 【参考方案1】:

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

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

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

很抱歉,我无法为您提供更多帮助。

【讨论】:

这个反对意见被搁置了。它同样适用于所有其他形式(嗯,不适用于默认参数值形式)。由于其他形式向前发展,这不能(故意)为什么这种形式没有。 在这里试试:2ality.com/2015/09/function-names-es6.html。有一些关于“函数的名称总是在创建过程中分配”。你可能比我更了解,我不是 ES6 大师 :D【参考方案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());

【讨论】:

“我不确定有什么具体原因。” Allen Wirfs-Brock 说有,有“各种反对意见”,因此“没有达成共识” “在那个表格上,因此它被遗漏了。 “写作有什么限制吗” 没有,当然没有。 :-)【参考方案3】:

Allen Wirfs-Brock 的 replied on the es-discuss list 反对阻止 TC39 就 obj.foo = function() 表单达成共识:

...对于

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

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

为了

obj[someSymbol] = function() 

它会将 Symbol 值作为 name 的值泄漏

对于

 table[n]=function() 

name 可能是一个数字字符串

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

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

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

总而言之,显然在做出决定时,这些反对意见占据了上风(现在很可能也是如此),这就是为什么这种形式不会自动命名函数,而许多其他形式会这样做。

【讨论】:

以上是关于为啥 `obj.foo = function() ;` 没有将名称 `foo` 分配给函数?的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript 的 this 原理

JavaScript 的 this 原理

2021.06.22(JavaScript中的this理解)

JavaScript中this这号人物和callapply的详解

JS 深入浅出This指向(精简)

JavaScript中this的一些坑