JavaScript 变量提升
Posted 旗smile
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript 变量提升相关的知识,希望对你有一定的参考价值。
变量声明是所有的编程语言中最基础部分之一。然而,javascript 有一个怪异点,称之为变量提升(hositing),这个能够让一个看上去无关紧要的声明变成一个小bug。这篇文章解释了变量提升(hositing)是什么,以及你该如何避免这个大坑。
JavaScript 是特别灵活的语言,几乎允许你在任何地方声明变量。比如,下方的立即执行函数表达式(IIFE)声明了2个变量,然后将他们用一个弹框显示他们。作为附注,你应该永远不要用弹框,不过我们正在这里证明这一点。
(function()
var foo = 1;
var bar = 2;
var baz = 3;
alert(foo + " " + bar + " " + baz);
)();
这个看上去像是一个机智的 JavaScript 代码。就像预期那样,他显示了字符串 "1 2 3"
。现在,假设移动弹框位置,就下下方那样。
(function()
var foo = 1;
alert(foo + " " + bar + " " + baz);
var bar = 2;
var baz = 3;
)();
如果有人真的这么写代码,那么这可能就要报错了。很显然,弹框在 bar
和 baz
声明之前发生。然而这是完全有效的 JavaScript ,这完全不会抛出异常。相反,弹框会显示 "1 undefined undefined"
。
基于上一个实验,似乎你能够引用之前不存在的变量。现在,让我们做一个相同的 IIFE,但是移除 baz
声明,就想下方那样。马上,我们有个引用错误(ReferenceError)
,因为 baz
没有定义。
(function()
var foo = 1;
alert(foo + " " + bar + " " + baz);
var bar = 2;
)();
这真的很有趣。为了理解这里发生了什么,你需要理解变量提升(hoisting)。变量提升(hoisting)是 JavaScript 编译器的行为,将所有的变量和函数声明移至当前作用域的最高处。然而,只有声明被提升了。任何赋值行为都被留在他们所在的地方。因此,我们第二个例子 IIFE 实际上等同于以下 代码:
(function()
var foo;
var bar;
var baz;
foo = 1;
alert(foo + " " + bar + " " + baz);
bar = 2;
baz = 3;
)();
现在,你可以搞清楚为什么第二个例子不会抛出异常。变量提升之后(hoisting),bar
和 baz
实际上在弹框之前就已经被定义了,尽管显示undefined。在第三个例子中,baz
被完全移除了。因此,没有可以提升的变量,导致弹出框抛出异常。
函数变量提升(hoisting)
就像之前提到的那样,函数声明也是可以被提升的。然后,赋给变量的函数却没有提升。比如,在下方的代码中会像预期那样运行,因为函数声明被提升了。
foo();
function foo()
alert("Hello!");
然而,下方例子苦逼地失败了。foo
这个变量声明在函数被调用之前提升了。然后,因为foo
的赋值没有提升,因此抛出了尝试调用非函数变量的异常。
foo();
var foo = function()
alert("Hello!");
;
总结
变量提升(hoisting)很容易理解,但是却是 JavaScript 语言中经常被忽视的细节。没有对变量提升(hoisting)有一个合适的理解,你的程序很容易有小bug。为了帮助你远离这些bug,许多开发者(和静态分析工具)提倡在每一个作用域开头放一个单独变量声明。既然这是 JavaScript 编译器如何检测你的代码的基础,那么对这条规则来说是有效的——即使我打破了规则。
以上是关于JavaScript 变量提升的主要内容,如果未能解决你的问题,请参考以下文章