今天去面试了,总体感觉很不错,整个公司还有人的气氛都很棒,希望能顺利通过。
问到 JS 一些细节问题的时候发挥比较糟糕,有些是知道反应得太慢,有些是压根没接触过,还是积累的太少了。这篇的 JS 变量提升问题就是从没有接触过的,网上一搜一大把,实在是不应该。为了不给信息爆炸添砖加瓦。。。照例尝试就这个问题扯一些别的理解。
var foo = 1;
function bar() {
if (!foo) {
var foo = 10;
}
alert(foo);
}
bar();
运行结果为:10
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
alert(a);
运行结果为:1
此前有在资料上扫到过一眼,所以听到答案后第一时间反应过来是变量提升,但对变量提升的具体行为则不了解了。在蝴蝶书里有一笔带过提了一句“通常编写代码提倡把变量声明尽量贴近变量使用的位置,以提供上下文参考,但 Javascript 没有块级作用域,所以反而推荐在函数的顶部给出所有用到变量的声明。”(大意是这样,书没在手边,不确认了)
当时不太理解没有块级作用域为什么会影响这个,现在了解了变量提升就很容易理解了。
以上面第一段程序为例,其实它等价于:
var foo = 1;
function bar() {
var foo; // foo === undefined
if (!foo) { // !foo === true
foo = 10;
}
alert(foo); // alert(10)
}
bar();
可以看到,在 bar 函数内部的局部变量声明 var foo
被提升到了函数体的顶部,所以 !foo
成了 !undefined
结果为 true
。而后又被赋值 10
,至于全局变量 foo
完全没参与进来。
虽然考点是变量提升,但个人认为,答出变量提升顶多合格分,这道题还有更实用的现实意义。
由于 !foo
所在的位置在提升前位于函数体第一行,而且 var foo
在 if
语句的块内,增加了隐蔽性。即使开发者了解变量提升,如果看漏了下面的 var foo
很容易就会误认为是在使用全局的 foo
。只要函数体稍微复杂一点,这种事情就很容易发生了。
因此才会有前面蝴蝶书的那一段话,建议把函数内用到的所有变量的声明写在函数开头。
记得此前还听过一个类似的故事,一个 c 语言项目中隔三差五总会遇到在 if
里比较相等结果写成了赋值语句产生的 bug :
if (a=1) {
...
}
被这情况烦了多次之后,定下了这样一个要求,if
内的相等判断统一把常量写左边:
if (1=a) { // Error! 常量无法被赋值
...
}
这样一来,原来防不胜防的隐蔽 bug 变成了一个语法分析阶段就会暴露无遗的编译错误。
(当然,早有更加好的办法了,像上面中 if
括号内赋值的写法,在 lint 的过程中就会被提醒存在潜在问题,所以这里只是个例子。)
感觉工程上的许多规定真的很有趣,一个小小的限制,就能帮助你绕过许多的坑。不能光爬坑,爬完了还得给坑立个绕行路牌,这些积累下来的东西,才真正能体现出经验的价值吧。
希望自己也能尽快积累成一个靠谱的前端工程师 :-P