简写语法方法定义的标识符范围



根据我的经验和"为什么使用命名函数表达式?"中的信息?和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.namefoo,但foo不能从其内部访问。

关于规范,观察到的行为是否正确?规范中对此有何定义?

函数有一个名称,因为obj.foo.namefoo,但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方法中创建的(搜索它)。特别有趣的情况是IsAnonymousFunction­Definition调用,该调用检查表达式是否不包含命名令牌。

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将为函数命名。

最新更新