专栏首页Alan's LabJS 变量提升

JS 变量提升

今天去面试了,总体感觉很不错,整个公司还有人的气氛都很棒,希望能顺利通过。

问到 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 fooif 语句的块内,增加了隐蔽性。即使开发者了解变量提升,如果看漏了下面的 var foo 很容易就会误认为是在使用全局的 foo 。只要函数体稍微复杂一点,这种事情就很容易发生了。

因此才会有前面蝴蝶书的那一段话,建议把函数内用到的所有变量的声明写在函数开头。

记得此前还听过一个类似的故事,一个 c 语言项目中隔三差五总会遇到在 if 里比较相等结果写成了赋值语句产生的 bug :

if (a=1) {
    ...
}

被这情况烦了多次之后,定下了这样一个要求,if 内的相等判断统一把常量写左边:

if (1=a) { // Error! 常量无法被赋值
    ...
}

这样一来,原来防不胜防的隐蔽 bug 变成了一个语法分析阶段就会暴露无遗的编译错误。

(当然,早有更加好的办法了,像上面中 if 括号内赋值的写法,在 lint 的过程中就会被提醒存在潜在问题,所以这里只是个例子。)


感觉工程上的许多规定真的很有趣,一个小小的限制,就能帮助你绕过许多的坑。不能光爬坑,爬完了还得给坑立个绕行路牌,这些积累下来的东西,才真正能体现出经验的价值吧。

希望自己也能尽快积累成一个靠谱的前端工程师 :-P


本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • windows 10 私人不负责任评测(多图预警)

    最牛的一个: Mac 下 Flash 一直是个痛,只有用虚拟机的 Win 7 才勉强敢看,但拿 Win 10 试了一盘三国杀+两部腾讯视频(拿 Mac 看过腾讯...

    Alan Zhang
  • iOS一点点 - TableView 拼音序排序(汉字转拼音、简繁体转换、日文转罗马音等)

    Introduction to ICU General Transforms Transform Rule Tutorial 使用ICU进行拼音转汉字暂时似乎也...

    Alan Zhang
  • 填一填用了半个月 ionic 遇到的坑

    这篇没什么东西可扯,基本是 Q&A 形式。不定时更新,不用 Ionic 了就不更新。。。

    Alan Zhang
  • R中的管道操作符%>%

    管道是一种强大的工具,可以清楚地表示由多个操作组成的一个操作序列。管道%>% 来自于magrittr 包。因为tidyverse 中的包会自动加载%>%,所以一...

    生信编程日常
  • VC和GCC成员函数指针实现的研究(二)

    调用的时候主要看(c.*vptr2)()的代码。因为(c.vptr1)()生成的和单继承一样。而由于它们最终都转向vcall,所以vptr2的时候调整了虚表指针...

    owent
  • 【译】通过可选链操作符重构大型代码库的经验教训

    如今,可选链操作符已经被支持了。我决定用其来重构Mavo(当然了,还需要提供一个转译版本来适配不支持该特性的浏览器)。我等这一刻已经很久了,这是我认为自箭头函数...

    腾讯IVWEB团队
  • 你不知道的javaScript笔记(2)

    this和对象原型 this是一个很特别的关键字,被自动定义在所有函数的作用域中 // foo.count 是0,字面理解是错误的     function f...

    用户1197315
  • VC和GCC成员函数指针实现的研究(三)

    因为是兼容虚继承和非虚继承的,所以赋值的部分的汇编是一样的。这里就不贴了。关键在于执行期它是怎么找到虚基类的。请往下看:

    owent
  • JS入门难点解析7-this

    (注1:如果有问题欢迎留言探讨,一起学习!转载请注明出处,喜欢可以点个赞哦!) (注2:更多内容请查看我的目录。)

    love丁酥酥
  • NYOJ----次方求模

    次方求模 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 求a的b次方对c取余的值 输入第一行输入一个整数n表示测试数据的组数...

    Gxjun

扫码关注云+社区

领取腾讯云代金券