首页 > 解决方案 > JavaScript 中 for-body 的运行时语义

问题描述

规范中,JavaScript 中 for-body 评估的运行时语义是:

在此处输入图像描述

运行以下代码时,我希望创建两个函数对象,每个 for-body 迭代一个。

for(let x = 0; x < 2; x++) {
    function f() {}
}

这是否包含在 4.b. 中?在上面的规范片段中?

标签: javascript

解决方案


是的,确实是EcmaScript 2015 规范的第 13.7.4.8 节,第 4.b 点描述了for循环体(语句,如13.7.4.7中标识)被评估,这在您的示例中意味着f创建了函数对象.

这发生在每次迭代中(步骤 4)。

您可以按如下方式监视双重创建:

let set = new Set;

for(let x = 0; x < 2; x++) {
    function f() {}
    set.add(f);
}

console.log(set.size); // 2 in Chrome, Firefox and Edge

我在 Chrome、FireFox 和 Edge 中得到输出 2。一些报告 1 作为输出。这很可能是 JavaScript 引擎的一种优化。

在这种情况下,mdn指出:

函数可以有条件地声明,也就是说,一个函数语句可以嵌套在一个if语句中,但是结果在不同的实现中是不一致的,因此这种模式不应该在生产代码中使用。对于条件函数创建,请改用函数表达式。

这句话也适用于循环结构,因为它们也有条件地执行。因此,使用函数表达式可以获得更可靠的结果:

let set = new Set;

for(let x = 0; x < 2; x++) {
    var f = function f() {};
    set.add(f);
}

console.log(set.size); // 2 in Chrome, Firefox and Edge

请注意,在这两个片段中,f都不是在for主体范围内,而是在周围范围内。所以f在循环完成后可以访问。


推荐阅读