You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Variables declared with var or created by function declarations in non-strict mode do not have block scope. Variables introduced within a block are scoped to the containing function or script, and the effects of setting them persist beyond the block itself. In other words, block statements do not introduce a scope.
解释下,就是当使用 var 进行声明或创建函数声明时,在非严格模式下不具有块级作用域。
但是看了文章开头的代码,你就会觉得这段描述并不全面。
然后继续查看 mdn 的话,就会发现一句短小精悍的话:
In non-strict code, function declarations inside blocks behave strangely. Do not use them.
一道题引发的一系列思考🤔
出题
最近群内一直在聊一道题,大概题目如下:
这段代码输出什么?为什么?
常规思考
首先,按照自己的理解,来看下这个题目。
正常思路,抛开一切乱七八糟的内容
按照这种思想,那输出的结果为:
但是!!!,事实并非如此。
意外发生
我在 Chrome 中运行这段代码时,发现了与预想截然不同的结果:
为了排除内核差异,在各内核中的执行结果如下:
WTF!!! 发生了什么?
从执行结果看,可以看出 v8 和 SpiderMonkey 实现一致,但与 JavaScriptCore、ChakraCore 均不相同。
哪里出了问题?
那究竟是哪里的问题?变量?函数?
社区解释
于是乎,查阅资料。。。
大概会有如下的机制
类似于
那我们的代码,如果按照这种思考方式来改写的话,我觉得转换后的代码应该是这样滴:
看下输出,符合 v8 和 SpiderMonkey 的结果:
真相
在查阅了大量资料后,以及爱民老师的指导下,最终接近了真相。
这道题主要原因出在块级作用域(block)中的
function
:MDN
MDN 中关于 block 的解释是:
解释下,就是当使用 var 进行声明或创建函数声明时,在非严格模式下不具有块级作用域。
但是看了文章开头的代码,你就会觉得这段描述并不全面。
然后继续查看 mdn 的话,就会发现一句短小精悍的话:
函数声明在 block 中的表现会很奇怪,应该避免使用它们!
虽然在 MDN 中没有找到答案,但是我们得到一个关键信息,就是非严格模式下,不要在 block 中声明函数。
嗯,MDN 没找到答案,只能去 ecma 中找答案了。
ecma262
我们知道,在 ES5 以及之前,ECMAScript 并没有定义块级函数这种语法:函数声明作为 block 语句中的一个元素出现。但是当时很多浏览器内核中 ECMAScript 实现将其作为一种扩展进行了各自的支持,而这带来的结果是不同的实现中相同语法的语义却不同。
而我们这里主要参考 ecma262 的标准附录 B3.3 Block-Level Function Declarations Web Legacy Compatibility Semantics。
从规范 B3.3 中我可以看到如下信息:
上面中提到了三种情况,第一种情况属于正常范畴
但是,第2种和第3种情况针对于我们所熟知的规范进行了修改调整:
而这些属于兼容性语义的范畴,因此,每个内核的实现可能存在差异。
其实出现本文开头题目输出和预期不符的问题的说明,主要出现在B3.3.2 GlobalDeclarationInstantiation
其他大概含义是,全局中的 declaredFunctionNames 和 declaredVarNames 都会存储在 declaredFunctionOrVarNames 列表当中。
而直接包含在 script 中的 block,case 子句或者 default 子句的语句列表中的每个函数声明,都会进行上图中的操作。
大概意思是:
用代码解释:
如需进一步验证,需深入阅读 ecma 标准以及 v8 等内核的相关实现。
至此,已合理解释了这个问题。
总结
如有错误,恳请斧正。
参考链接
The text was updated successfully, but these errors were encountered: