阅读 125

你真的理解变量提升吗?

什么是变量提升

变量提升基础概念其实很好理解:变量提升即将变量声明提升到它所在作用域的最开始的部分。 但是我们真的遇到变量提升的题目时,却反而容易遗忘。如:

if (! "a" in window) {
    var a = 1;
}

alert(a);  //undefined
复制代码

第一遍阅读代码的感觉是这样的:如果全局对象中不存在a这个属性没,那么设置全局变量a=1。 那么答案应该等于1才对,为什么是undefined呢?
因为a被变量提升了!
再次解析上面代码,其实相当于以下代码:

/**
上面这段代码相当于
**/
var a;
if (! "a" in window) {
    a = 1;
}
alert(a); 
复制代码

首先,我们需要知道一个概念:js运行时,会分两步进行操作,先进行解析,再执行

解析,也就是创建变量和声明函数。js会将所有var定义的变量和function都提升到作用域的顶端。并检查时候有语法错误。如:Uncaught ReferenceError等。

执行,js从上向下开始运行代码。

这样我们就可以清晰地看出a是undefined了。


为什么要有变量提升

参考自:segmentfault.com/q/101000001…

之前一直不理解为什么要有变量提升,这只是一个js设计的缺陷吗?如果是缺陷为什么不一开始就解决掉他呢?(现在es6已经使用let代替var)他之前有没有什么存在的意义呢?

提高性能

解析的过程中,还会为函数生成预编译代码。在预编译时,会统计该函数声明了哪些变量、创建了哪些函数(注:这里就是声明提升),并对函数的代码进行压缩,去除注释、不必要的空白等。这样做的好处是每次执行函数时都可以直接为该函数分配栈空间(不需要再解析一遍去获取函数中声明了哪些变量,注:这也是声明提升的好处),并且代码执行更快(因为压缩而变短了)。两个好处都会提高执行函数的性能。

容错性更好

我们知道,JS是一种脚本语言,在发布之后很长时间内都没有为程序员提供编译器、调试器、语法检查器等工具。在很长一段时间内其地位始终是Web页面的附属品,仅仅用来给页面添加一些非必要的动态效果,并且其开发和部署也具有很强的随意性,未经过调试和测试的代码比比皆是。

简而言之,以前的js并不是很被人看好,只当他是个脚本语言,通过这个方法可以简化开发,减少报错,增加容错率。

函数提升的必要性

其实提升功能不可替代的情况是用在函数提升上。如:

function func1() {
    func2();
}
fun1();
function func2() {
    alert('success');
}
复制代码

这是我们很常见的申明函数的情况,如果没有函数提升,在执行到fun2()时会直接报错,因为此时func1还并未定义。


那么我们最后来讨论一下,变量提升真的是设计缺陷吗?
我认为可能是的。因为在现在的开发中,变量提升只会加大我们对代码的理解的难度。 有时候会造成我们意想不到的问题,造成不是我们想要的结果,(如上面的题目)而且很难排查。也正如大众对JavaScript的评价就是:它的优秀之处并非原创,它的原创之处并不优秀


常见面试题

9道面试题

参考自 www.jianshu.com/p/864b0003d…

写出下列显示的值

(function(){
    a = 5;
    alert(window.a);
    var a = 10;
    alert(a);
})();
复制代码

解题过程:这是利用了立即执行函数来模拟块级作用域的写法。因为函数提升就是把变量声明提升到它所在作用域的最开始的部分,所以上面代码相当于:

(function(){
    var a;    //局部变量a,默认值是undefined
    a = 5;    //因和局部变量名相同,因此全局变量a被覆盖,此处变成了给局部变量a赋值
    //alert(a);  弹出5
    //a只是变量,而不是属性 alert(a in window)返回false  ,参见http://segmentfault.com/q/1010000002883076 的第一个回答
    alert(window.a);  
    a = 10;
    alert(a);
})();
复制代码

所以答案是 undefined和10

关注下面的标签,发现更多相似文章
评论