根据我的经验和"为什么使用命名函数表达式?"中的信息?和kangax.github.io:命名函数表达式,很清楚为什么下面的两个例子会产生给定的输出:
示例1:
var f = function foo() {
console.log(foo);
}
console.log( typeof foo === "undefined" ); // true
console.log( typeof f !== "undefined" ); // true
console.log( f.name ); // foo
示例2:
var obj = {
fooA: function foo() {
console.log('fooA -> ' + foo.toString());
},
fooB: function foo() {
console.log('fooB -> ' + foo.toString());
}
}
obj.fooA(); // the source of fooA
obj.fooB(); // the source of fooB
console.log(typeof foo === "undefined"); // true
但我试图弄清楚为什么标识符不能用于以下示例中的封闭范围:
var obj = {
foo() {
console.log(typeof foo === "undefined"); // true
}
}
obj.foo();
console.log(obj.foo.name); // foo
我想它是在某个地方定义的,但关于这一点的信息似乎分布在整个规范中。我发现的唯一明确的声明是关于MDN:方法定义:
注意:简写语法使用命名函数而不是匿名函数(如…foo:function(){}…)。可以从函数体调用命名函数(这对于匿名函数来说是不可能的,因为没有可引用的标识符)。有关更多详细信息,请参阅函数。
但在我的选择中,这与观察结果相矛盾,因为它说这种函数是一个命名函数,因此应该可以从函数体访问它。
函数有一个名称,因为obj.foo.name
是foo
,但foo
不能从其内部访问。
关于规范,观察到的行为是否正确?规范中对此有何定义?
函数有一个名称,因为
obj.foo.name
是foo
,但foo
不能从其内部访问。
是。这是ES6引入的一种新型函数:命名的匿名函数1。嗯
ES6函数的name
属性不再是从function
关键字和左括号之间的标记派生的,而是从分配给它的变量或属性名称派生的
var obj = {
foo() { … }
}
在语义上等同于
var obj = {
foo: function() { … }
}
在ES6中,两者都创建了一个.name
为"foo"
的函数(参见§14.3.9和§12.2.6.9)。
然而,这个函数不是一个命名函数表达式,它在中间闭包范围中创建了一个foo
常量,允许它引用自己。
如果你想在函数定义中有一个自引用,你可以使用this.foo
。
关于规格,观察到的行为是否正确
是。MDN似乎又出现故障了。
…规范中在哪里定义了这一点?
基本上在整个第14章:函数和类中。
特别是,§14.1.20中规定了命名函数表达式的行为,重点是在匿名函数表达式的评估中找不到的funcEnv
。
.name
属性是在从所有规范调用的抽象SetFunctionName
方法中创建的(搜索它)。特别有趣的情况是IsAnonymousFunctionDefinition
调用,该调用检查表达式是否不包含命名令牌。
1:我刚刚编造了这个词。如果您没有注意到:-)
简短回答:
您需要使用this.foo
({
foo(x) {
return x > 3 ? x : this.foo(x+1);
}
}).foo(1); // => 4
这与你有这个没有什么不同:
({
foo: function(x) {
return x > 3 ? x : this.foo(x+1);
}
}).foo(1); // => 4
命名函数可以从函数体调用
对,所以如果您命名,您可以在没有this
:的情况下使用它
({
foo: function foo(x) {
return x > 3 ? x : foo(x+1);
}
}).foo(1); // => 4
观察到的行为与规范有关是否正确,规范中在哪里定义了这一点?
这部分我不能为你回答,对不起。
babel.js
如果您使用babel 进行转换
let x = {foo() {}};
你会得到
var x = {foo: function foo() {}};
因此,如果您对代码进行可转换,它将正常工作,因为Babel将为函数命名。