

乍一看,大伙们都不约而同地回答,输出都是10啊,然后问为何,就没有然后了......
如果你也认为输出都是10,那么“恭喜”你答错了!有趣吧,这其中的“奥妙”就在if语句块内声明函数,即有条件的创建函数(在不同浏览器中有不同的效果,本文讲解仅代表在当前版本chrome浏览器中的结果分析)。
如果去掉外层if语句,再来看题:
var d = 0;
//if(true){
d = 1;
function d(){}
d = 10;
console.log(d);
//}
console.log(d);
这时,毫无疑问都是输出 10 呢。可为何加上外层if语句就会有所不同,甚至给人诡异的感觉呢?
函数可以被有条件来声明,也就是说函数声明可能出现在一个
if 语句里。有的浏览器会将这种有条件的声明看成是无条件的声明,即是无论条件是true还是false,浏览器都会创建函数。因此,它们不应该被使用。
但,大部分浏览器都没有遵守这个ES5标准,各浏览器JS引擎生产商不同,可以有自己的实现方式:
- 允许在块级作用域内声明函数
- 函数声明类似于
var,即会变量提升到全局作用域或函数作用域的最顶端 - 同时,函数声明还会提升到其所在块级作用域的最顶端
注意:以上3条规则只针对ES6浏览器实现有效,其他环境下的实现不用遵循,仍将块级作用域的函数声明作let处理即可。
如果对变量提升和函数提升不是很清楚的童鞋,可以参看JavaScript:变量提升和函数提升。
下面就将题目代码解析如下:
//块级作用域内的function d() {}类似于var ,会在全局作用域这里声明一个同名变量d,值为undefined
console.log("第1行:",window.d,d); //undefined undefined
var d = 0;
if(true){
//function d() {}函数声明会提升到块级作用域最顶端
console.log("第2行:",window.d,d); // 0 function d() {}(函数对象)
d = 1;
console.log("第3行:",window.d,d); // 0 1
function d() {} //执行到函数声明原始位置这一行,才会改变块级作用域外(全局作用域)的变量d。会将块作用域里的d赋值到全局同名变量d
console.log("第4行:",window.d,d); //1 1
d = 10;
console.log("第5行:",window.d,d); //1 10
}
console.log("第6行:",window.d,d); //1 1
总结:
-
if 语句块内的函数声明首先会在块级作用域外(全局作用域)定义一个同名变量d ,并初始化赋值undefined; -
if 语句块内的函数声明会提升到块级作用域最顶端; - 执行到函数声明原始位置时,块级作用域内的函数变量名d的值赋值给外部同名变量d;
- 由于各浏览器实现不同,不建议在
if 语句块内使用函数声明式定义函数,可以使用函数表达式形式代替。
到此,这道题其中蕴含的“奥妙”想必也都能理解了哦,也不枉我花了时间对其的研究啊!还不能理解的小伙伴们,就多理解几遍看看呢,只要肯钻研学习,没什么学不会的哦!
如果你觉得这篇文章对你有帮助,请点赞支持一下哦!