问题描述
以下代码在OSX的Safari 13.0.4中打印1
.
The following code prints 1
in Safari 13.0.4 on OSX.
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
此行为是否与第13.7.4.8节兼容?(请参见下文)?
Is this behavior compatible with section 13.7.4.8 (see below) of the specification?
请注意:Node 13.9.0,Chrome 80.0.3987.122和Brave 1.3.118打印2
.
Note that: Node 13.9.0, Chrome 80.0.3987.122, and Brave 1.3.118 print 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 中的错误.但是,您已经注意到,它仅在全局(或eval
)范围中发生,并且仅在草率模式下发生.
Yes, this is a bug in Safari. However, as you noticed, it only occurs in global (or eval
) scope and only in sloppy mode.
通常,这些绝对应该是不同的函数实例,而不是悬挂在块之外.但是,作为浏览器的Safari确实实现了规范附件B3.3中的块级功能声明Web旧版兼容性语义(请参见此处以获取详细信息).在ES6和 ES7 ,尽管它们确实仅适用于函数内部的语句块.仅由于 ES8 ,也为全局和eval范围中的声明实例化指定了它们.
In general, these should definitely be distinct function instances, not getting hoisted outside of the block. However, Safari - being a browser - does implement the Block-Level Function Declarations Web Legacy Compatibility Semantics from Annex B3.3 of the specification (see here for details). In ES6 and ES7, these did apply only to block statements inside functions though. Only since ES8, they are also specified for declaration instantiations in global and eval scopes.
似乎Safari尚未从ES8采纳该更改,并保留了自己的版本(不兼容) pre-ES6语义用于全局范围内的块范围声明,它们在此处完全提升了声明.
It seems that Safari did not adopt that change from ES8 yet, and has kept their own (noncompliant) pre-ES6 semantics for block-scoped declarations in the global scope, where they hoist the declaration completely.
这篇关于Safari的这种行为是否违反ECMAScript规范?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!