问题
最近遇到一道面试题,简单可以理解为
{
function a () {}
a = 1
}
console.log(a)
// 打印 ƒ a () {}
这个是不符合我的认知的,因为 ES6 之后,使用 let const 和函数声明都是应该有块作用域的。
但是这里很明显块作用域没有生效。而且更诡异的是,如果说块作用域没有生效,那也应该打印 1 而不是 f a () {}
原因
经过几番测试和搜索,在这里找到可以解释的答案。上述代码可以理解为
var a = undefined
{
var _a = function () {}
a = _a
_a = 1
}
console.log(a)
有几点需要注意的
- 只有在非严格模式会这样,严格模式下是完全符合预期的
'use strict' { function a () {} a = 1 } console.log(a) // 报错 Uncaught ReferenceError: a is not defined at <anonymous>:6:13 - 在块作用域外面可以访问,就如同 var 声明一样,但是会在块作用域内部被重新赋值一次
- 有两次声明提升,第一次是在块作用域外被初始化为
undefined,第二次是在块作用域内部被初始化为f a () {} - 有临时死区,但是不同于
letconst的临时死区,而是在块作用域外部,在执行到function a () {}之前,调用a则会报错{ a() function a () {} } // 不报错a() { function a () {} } // 报错 Uncaught TypeError: a is not a function at <anonymous>:1:1 - 设计成这样的原因可能是因为 ES6 的这种改变属于非常重大的改变,会影响代码的运行,为了尽可能兼容旧代码,在没有更好选择的情况下,只好通过使用严格模式来进行区分
总结
使用 'use strict',远离这种诡异事件