从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用于属性引用)。
从上面重申:为什么不呢?当然必须存在特定的原因,这是不可取/不可能的。它是什么?
答案 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(){});