[英]function.name returns empty string if the function is added to an object by property
Consider this code example:考虑这个代码示例:
let test = {
test: function(){}
}
test.print = function(){}
console.log(test.print.name) // Outputs ""
console.log(test.test.name) // Outputs "test"
console.log(test) // Outputs { test: function(){}, print: function(){} }
Why is there a difference between the name
properties of these two functions?为什么这两个函数的
name
属性有区别?
The specification tells you:规范告诉你:
({ test: function(){} })
13.2.5.5 Runtime Semantics: PropertyDefinitionEvaluation
13.2.5.5 运行时语义:PropertyDefinitionEvaluation
PropertyDefinition : PropertyName
:
AssignmentExpressionPropertyDefinition : PropertyName
:
AssignmentExpression
- Let propKey be the result of evaluating
PropertyName
.让propKey成为评估
PropertyName
的结果。- […]
[…]
- If IsAnonymousFunctionDefinition ( AssignmentExpression ) is true, then
如果IsAnonymousFunctionDefinition ( AssignmentExpression ) 为真,则
- Let propValue be?
让propValue成为? NamedEvaluation of AssignmentExpression with argument
propKey
.带参数propKey的AssignmentExpression的
propKey
。- Else,
别的,
- […]
[…]
In step 3, IsAnonymousFunctionDefinition of the expression function(){}
returns true , because it is a function definition , and it lacks a BindingIdentifier .在步骤 3 中,表达式
function(){}
的IsAnonymousFunctionDefinition返回true ,因为它是 function 定义,并且缺少 BindingIdentifier 。
Therefore, a NamedEvaluation is performed: the function is created with "test"
as the value of the name
property.因此,将执行NamedEvaluation :创建 function,并将
"test"
作为name
属性的值。
test.print = function(){};
13.15.2 Runtime Semantics: Evaluation
13.15.2 运行时语义:评估
AssignmentExpression : LeftHandSideExpression
=
AssignmentExpression赋值表达式: LeftHandSideExpression
=
赋值表达式
- Let lref be the result of evaluating LeftHandSideExpression .
令lref为评估LeftHandSideExpression的结果。
- […]
[…]
- If IsAnonymousFunctionDefinition ( AssignmentExpression ) and IsIdentifierRef of LeftHandSideExpression are both true , then
如果LeftHandSideExpression的IsAnonymousFunctionDefinition ( AssignmentExpression ) 和IsIdentifierRef都为true ,则
- Let rval be NamedEvaluation of AssignmentExpression with argument lref .[[ReferencedName]].
令rval为带有参数lref .[[ReferencedName]] 的AssignmentExpression的NamedEvaluation 。
- Else,
别的,
- Perform?
履行? PutValue ( lref , rval ).
放置值( lref , rval )。
- […]
[…]
In step 3,在第 3 步中,
function(){}
returns true , just like it does in the other snippet,function(){}
的IsAnonymousFunctionDefinition返回true ,就像在另一个片段中一样,test.print
returns false : it's a MemberExpression , not an Identifier .test.print
的IsIdentifierRef返回false :它是MemberExpression ,而不是Identifier 。 Therefore, step 4, the “Else” case, is taken and no NamedEvaluation is performed.因此,采取步骤 4,即“Else”情况,不执行NamedEvaluation 。
The only difference is the additional IsIdentifierRef step, which is also the key to finding the rationale (on esdiscuss.org):唯一的区别是额外的IsIdentifierRef步骤,这也是找到基本原理的关键(在 esdiscuss.org 上):
2015-07-25 14:22:59 UTC adbergi at web.de writes: 2015-07-25 14:22:59 UTC adbergi 在 web.de写道:
[If] a function (or class) definition is assigned to a property of an object, [the function automatically being given the name of the target identifier] doesn't happen:
[如果] function(或类)定义被分配给 object 的属性,[function 自动发生:给出目标标识符的名称] 不会
var o = {}; o.someProperty = function() { … }; o.otherProperty = class { … };
I don't see any reason for not doing this.
我看不出有任何理由不这样做。 [It] just seems to be advantageous and make the language more consistent.
[它] 似乎是有利的,并使语言更加一致。 I'm quite sure it wouldn't break any compatibility.
我很确定它不会破坏任何兼容性。
This is one of the replies:这是回复之一:
2015-07-26 19:48:15 UTC Allen Wirfs-Brock writes (emphasis mine): 2015-07-26 19:48:15 UTC Allen Wirfs-Brock写道(强调我的):
[T]he possibility that the property key is a symbol is a primary reason that this expression form does not set the
name
property .[T]属性键是符号的可能性是这种表达形式没有设置
name
属性的主要原因。There may also be security concerns .
也可能存在安全问题。 The
name
property potentially leaks via the function object the name of the variable it is initially assigned to.name
属性可能会通过 function object 泄漏它最初分配给的变量的名称。 But there isn't much someone could do with a local variable name, outside of the originating function.但是除了原始的 function 之外,没有人可以对局部变量名做太多事情。 But a leaked property name potentially carries a greater capability.
但是泄露的属性名称可能具有更大的功能。
Allen goes on, 2015-07-26 20:33:07 UTC :艾伦继续说, 2015-07-26 20:33:07 UTC :
TC39 reached consensus on automatically assigning the
name
property for expression forms like:TC39 就自动为表达式 forms 分配
name
属性达成共识,例如:Identifier
=
FunctionExpression标识符
=
函数表达式and so it is part of ES2015.
所以它是 ES2015 的一部分。 We did not have consensus on doing the same for:
我们没有就对以下方面做同样的事情达成共识:
MemberExpression
.
成员表达式
.
IdentifierName=
FunctionExpression标识符名称
=
函数表达式or
或者
MemberExpression
[
IdentifierName]
=
FunctionExpressionMemberExpression
[
IdentifierName]
=
FunctionExpressionso it is not part of ES2015.
所以它不是 ES2015 的一部分。 There were various objections that would have to be overcome before we could adopt that.
在我们能够采纳之前,必须克服各种反对意见。
Another comment, 2016-12-13 09:03:40 UTC by TJ Crowder states that it's unclear what those “various objections” were. TJ Crowder 于 2016 年 12 月 13 日09:03:40 UTC发表的另一条评论指出,目前尚不清楚这些“各种反对意见”是什么。 They link to the original proposal (archived from wiki.ecmascript.org, 2016-09-15, last available version) which does list your expected behavior in an example:
它们链接到原始提案(来自 wiki.ecmascript.org,2016-09-15,最后可用版本),该提案确实在示例中列出了您的预期行为:
obj.property = function(){}; // "property"
But keep in mind that this was still an unfinished proposal back then.但请记住,当时这仍然是一个未完成的提案。 When the proposal got accepted into the specification, it seems that it underwent some changes, but the proposal article didn't get changed to reflect these changes.
当提案被规范接受时,它似乎发生了一些变化,但提案文章并没有改变以反映这些变化。
This thread mentions certain TC39 meeting notes where this is discussed, but no link is provided.该线程提到了某些讨论此问题的 TC39 会议记录,但未提供链接。 Allen is claiming that this kind of information leak is the reason why TC39 couldn't reach a consensus on allowing this behavior.
Allen 声称这种信息泄露是 TC39 无法就允许这种行为达成共识的原因。 They mention 2017-01-28 15:46:54 UTC :
他们提到2017-01-28 15:46:54 UTC :
[F]or
cache[getUserSecret(user)] = function(){};
[F] 或
cache[getUserSecret(user)] = function(){};
it would leak the secret user info as the value ofname
.它会将秘密用户信息作为
name
的值泄漏。
Even though, as TJ Crowder mentions 2017-01-28 16:11:26 UTC , the same thing is possible with:即使,正如 TJ Crowder 提到的2017-01-28 16:11:26 UTC ,同样的事情是可能的:
cache = { [getUserSecret(user)]: function() {} };
“Is there a way to get the name of a function declared [like test.print = function(){};
“有没有办法获得声明的 function 的名称 [like
test.print = function(){};
]?” ]?”
Not really.并不真地。 You could iterate through the object's entries and find candidates for key names where the value matches the function.
您可以遍历对象的条目并找到值与 function 匹配的键名的候选者。 But if the function is referenced by another key name, you may get multiple results.
但是如果 function 被另一个键名引用,您可能会得到多个结果。 Also, this gets more complicated if the key is a symbol .
此外,如果键是符号,这会变得更加复杂。
const test = { test: function(){} } test.print = function(){}; test.someOtherAliasForPrint = test.print; test[Symbol("someSymbolForPrint")] = test.print; console.log( "Possible function names:", Object.entries(Object.getOwnPropertyDescriptors(test)).filter(([key, { value }]) => value === test.print).map(([key]) => key) ); console.log( "Possible function symbols:", Object.getOwnPropertySymbols(test).filter((symbol) => test[symbol] === test.print).map((symbol) => String(symbol)) // Or `.map(({description}) => description)` );
Your best bet is to define the method like this:你最好的办法是定义这样的方法:
test.print = function print(){};
However, consider using method syntax instead:但是,请考虑改用方法语法:
({
test(){},
print(){}
})
How you are defining print is using anonymous functions and accessing their name property will return ''.您如何定义 print 是使用匿名函数并访问它们的 name 属性将返回 ''。 Read more here
在这里阅读更多
If you still want to make the code work you can change your code like this:如果您仍然想让代码工作,您可以像这样更改代码:
test.print = function print() {
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.