结果是什么
先看两段代码。
代码1
JAVASCRIPTvar foo = 1;
if(foo){
var foo = 10;
}
alert(foo);
结果是显而易见的,就是 10.
分析:JavaScript 会自动忽略对同一变量的重复声明,即一开始用"var foo
"声明了变量foo
,后面的if
语句中的"var foo
"会被忽略掉。但后面的初始化语句则会覆盖前面的,故foo
最终被赋值为 10.
这没有任何让人困惑的地方。
代码2
JAVASCRIPTvar foo = 1;
function bar() {
if (!foo) {
var foo = 10;
}
alert(foo);
}
bar();
结果有点奇怪——依然是 10.
这其实是 JavaScript 语言一个强大但让人困惑的特性——声明提升,有人称之为 hoisting.
先来明确一下"声明"和"初始化"的概念。
声明与初始化
在 JavaScript 中,使用一个变量时一般都会进行声明和初始化的操作。
声明
使用var
操作符,后跟变量名(即一个标识符),可以定义一个变量,这便是变量的"声明"。如:
JAVASCRIPTvar name;
初始化
给一个变量赋值,即为"初始化"。如:
JAVASCRIPTname = 'Sky';
变量的声明和初始化可以写在同一条语句中:
JAVASCRIPTvar name = 'Sky';
只声明而没有进行初始化的变量,会保存一个特殊的值undefined
。
明确了这两个概念后,再来看什么是声明提升。
声明提升
JavaScript 引擎在处理函数代码时,会先做这样一个隐藏操作:
函数内部的所有声明(包括声明变量、用函数声明定义一个函数等),会全部提升到函数内部的最前端,而相应的初始化语句不受影响。
上面的代码2,其实等价于这样:
JAVASCRIPTvar foo = 1;
function bar() {
var foo;
if (!foo) {
foo = 10;
}
alert(foo);
}
bar();
这样看起来就清晰多了。
带来的启示
显然,这不是一个受人欢迎的特性——它使人困惑,还很容易给代码引入 bug。
那么,我们需要做的就是,在函数的顶部便声明好需要用到的所有变量,而不要在函数的各处随意声明变量。
不要这样写:
JAVASCRIPTfunction test(){
for(var i = 0; i < arguments.length; i++){
//其它代码
}
}
改成这样,形成良好的编码习惯:
JAVASCRIPTfunction test(){
//所有声明都统一放在顶部
var i = 0;
len = arguments.length;
for(; i < len; i++){
//其它代码
}
}