javascript中的作用域和闭包奇怪之处
这是昨天在TC39上提出的。你可以找到要点: 有人能给我解释一下这东西是怎么工作的吗?对于记录,它仅在非严格模式下工作javascript中的作用域和闭包奇怪之处,javascript,function,ecmascript-6,closures,hoisting,Javascript,Function,Ecmascript 6,Closures,Hoisting,这是昨天在TC39上提出的。你可以找到要点: 有人能给我解释一下这东西是怎么工作的吗?对于记录,它仅在非严格模式下工作 谢谢。我不想说我理解所有的微妙之处,但关键是附件B中几乎奇异的扭曲 该代码实际上就是这样的,其中f1是特定于块的词法环境的f的第二个副本(因此let如下所示): 当然,多亏了var提升,p和f都有效地在代码段顶部声明,初始值未定义: var f = undefined; var p = undefined; p = () => console.log(f); { le
谢谢。我不想说我理解所有的微妙之处,但关键是附件B中几乎奇异的扭曲 该代码实际上就是这样的,其中
f1
是特定于块的词法环境的f
的第二个副本(因此let
如下所示):
当然,多亏了var
提升,p
和f
都有效地在代码段顶部声明,初始值未定义
:
var f = undefined;
var p = undefined;
p = () => console.log(f);
{
let f1 = function f(){};; // Note hoisting
p(); // undefined
console.log(f1); // function f(){}
f1 = 1;
p(); // undefined
console.log(f1); // 1
f = f1; // !!!
p(); // 1
console.log(f1); // 1
f1 = 2;
p(); // 1
console.log(f1); // 2
}
B.3.3.1中的关键位是,它将内部f
(我在上面称之为f1
)的值传输到外部(在下面,f是字符串“f”
,即所声明函数的名称):
三,。评估FunctionDeclaration f时,执行以下步骤以代替14.1.21中提供的FunctionDeclaration评估算法:
a。让fenv成为运行执行上下文的可变环境
b。让fenvRec成为fenv的环境记录
c。让benv成为正在运行的执行上下文的词典环境
d。让benvRec成为benv的环境记录
e。让fobj去吧!benvRec.GetBindingValue(F,false)
f。表演fenvRec.SetMutableBinding(F,fobj,false)
g。返回NormalCompletion(空)
回想一下,变量环境是函数范围的,但是词法环境更受约束(对块)
当涉及到在函数声明{invalid | unspecified}(选择您的术语)的地方尝试规范化函数声明时,TC39有一条非常危险的导航路径,试图标准化行为,同时不破坏可能依赖于过去实现特定行为的现有代码(这是相互排斥的,但TC39正试图达成平衡).特别是关于托管?这个答案很好地解释了这一点:@codingitrigue:不,这不包括上面发生的事情,这是ES2015的附录B和TC39的产物,它们试图通过现有代码和历史上不一致的实现的严重危险水域进行引导。:-)@T.J.Crowder愿意更详细地解释吗<代码>函数f(){}通常会在一个正常的函数块中被提升,第一个
未定义的
应该已经打印了函数f声明,但是现在它在一个块中被定义了呢?@kstratis:我正在尝试,但是我要非常小心,不要给你错误的信息。仅供参考,相关bit是,尤其是步骤1.a.ii.3中的jiggery扑克。但我还没有详细阅读这一部分(遗憾的是,我不得不走出来),所以我手头没有现成的解释。有趣的情况。@T.J.Crowder谢谢你的链接,这个问题似乎比我想象的要复杂。你能不能对前两个p()?为什么它们显示为未定义的
?那一点最让我烦恼;我们已经有了提升,因此,在这一点上应该已经定义了f
。@kstratis记住提升并没有设置变量。它所做的只是更改声明,因此如果第10行有varx=5
,实际上代码是varx
位于文件顶部,然后在第10行x=5
。第1-9行仍然有x
相等未定义
,因为该值尚未设置。因此,在第4行执行console.log(x)
将产生未定义的。然而,如果您根本没有var x
,它将产生ReferenceError@kstratis:见上面弗拉兹的评论。我还添加了第二个代码段以使其显式化。@kstratis:这是我从规范末尾引用的位,它将内部f
(我称之为f1
)的值传输到外部f
。这真的很奇怪,但再一次,他们正试图引导最佳路线,以避免在混乱中编写太多代码。@kstratis:引用的位就是那个位,他们只是把它画出来而已。:-)(a) 和(b)基本上是说“获取整个函数的变量环境”,和(c)和(d)是说“获取块的词汇环境”,然后(e)从块的环境中读取内部f
(f1
)的值,并且(f)将该值写入变量环境中的外部f
。(是的,规格清晰如泥。)
var p = () => console.log(f);
{
let f1 = function f(){};; // Note hoisting
p(); // undefined
console.log(f1); // function f(){}
f1 = 1;
p(); // undefined
console.log(f1); // 1
var f = f1; // !!!
p(); // 1
console.log(f1); // 1
f1 = 2;
p(); // 1
console.log(f1); // 2
}
var f = undefined;
var p = undefined;
p = () => console.log(f);
{
let f1 = function f(){};; // Note hoisting
p(); // undefined
console.log(f1); // function f(){}
f1 = 1;
p(); // undefined
console.log(f1); // 1
f = f1; // !!!
p(); // 1
console.log(f1); // 1
f1 = 2;
p(); // 1
console.log(f1); // 2
}