以下代码在 OSX 上的 Safari 13.0.4 中打印 1

let set = new Set

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

console.log(set.size) // 1 in Safari non-strict mode


还:

let set = new Set

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

console.log(set.size); // 1 in Safari
for(let x of set) console.log(x.test) // 1 in Safari non-strict mode


和:

let set = new Set;

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

console.log(set.size); // 2 in Safari non-strict mode


此行为是否与规范的 section 13.7.4.8(见下文)兼容?

请注意:Node 13.9.0、Chrome 80.0.3987.122 和 Brave 1.3.118 打印 2

规范的 13.7.4.8:

(4.b 似乎相关)
The abstract operation ForBodyEvaluation with arguments test,
increment, stmt, perIterationBindings, and labelSet is
performed as follows:

1. Let V = undefined.

2. Let status be CreatePerIterationEnvironment(perIterationBindings).

3. ReturnIfAbrupt(status).

4. Repeat

  a. If test is not [empty], then

    i. Let testRef be the result of evaluating test.

    ii. Let testValue be GetValue(testRef).

    iii. ReturnIfAbrupt(testValue).

    iv. If ToBoolean(testValue) is false, return NormalCompletion(V).

  b. Let result be the result of evaluating stmt.

  c. If LoopContinues(result, labelSet) is false, return d.
     Completion(UpdateEmpty(result, V)).

  d. If result.[[value]] is not empty, let V = result.[[value]].

  e. Let status be CreatePerIterationEnvironment(perIterationBindings).

  f. ReturnIfAbrupt(status).

  g. If increment is not [empty], then

    i. Let incRef be the result of evaluating increment.

    ii. Let incValue be GetValue(incRef).

    iii. ReturnIfAbrupt(incValue).

最佳答案

是的,这是 Safari [1] 中的一个错误。但是,正如您所注意到的,它仅在全局(或 eval )范围内出现 ,而 仅在 草率模式下出现。

一般来说,这些绝对应该是不同的函数实例,而不是被提升到块之外。但是,作为浏览器的 Safari 确实实现了规范附录 B3.3 中的块级功能声明 Web 遗留兼容性语义(有关详细信息,请参阅 here)。在 ES6 和 ES7 中,这些确实只适用于函数内部的块语句。仅从 ES8 开始,它们也被指定用于全局和 eval 范围内的声明实例化。

Safari 似乎还没有采用 ES8 的更改,并且在全局范围内保留了他们自己的(不兼容的)pre-ES6 semantics 用于块范围的声明,在那里他们完全提升了声明。

1:可能是 #201695#179698 。 “我们在全局范围内不支持这个。我们在函数内部支持它,我相信 eval。我们仍然需要在全局范围内实现它。”

关于javascript - 这种 Safari 行为是否违反了 ECMAScript 规范?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/60416842/

10-11 23:08
查看更多