0%

About Argument & Function Are Hoisted in JavaScript

在很多语言如果是使用未定义的变量,通常会造成编译错误或者运行时抛出异常。
而对于JavaScript,则不会出现问题。下面的代码你拿去运行完全没有问题:

1
2
3
4
5
6
7
8
9
function test() {
alert(name);

var name = 'foo';

alert(name);
}

test();

jsfiddle

或者:

1
2
3
4
5
test();

function test() {
alert('foo');
}

jsfiddle

造成这些原因是都是JavaScript解析器的错,解析器会对当前作用域内的变量和函数的声明提前,
对于变量它的赋值操作则保留在原来的位置,而对于函数后面会单独说。

变量被提前

比如前面提到的第一个例子,实际在test函数内部是解释期间是这样的:

1
2
3
4
5
6
7
8
9
function test() {
var name;

alert(name);

name = 'foo';

alert(name);
}

再来看一个例子,各位想想下面的输出会是什么?

1
2
3
4
5
6
7
8
9
var name = 'foo';

(function () {
alert(name);

name = 'bar';

alert(name);
})();

在这里可以验证,jsfiddle

以及下面的代码会输出什么?

1
2
3
4
5
6
7
8
9
var name = 'foo';

(function () {
alert(name);

var name = 'bar';

alert(name);
})();

同样也可以在这里验证,jsfiddle

提示:只对当前作用域中声明的变量提前。

函数声明被提前

在一开始的例子中,test函数会被正确执行,所以是函数的整个定义都被提前了。
再来看下面的一个例子:

1
2
3
4
5
6
7
8
9
10
11
foo();

bar();

function foo() {
alert('foo');
}

var bar = function() {
alert('bar');
};

输出将会是:

1
2
alert foo
undefined is not a function

验证地址,jsfiddle
看错误的时候,记得developer tools.

会出现这两个不同结果是因为,函数被提前分两种:

  • 函数声明被提前
  • 函数赋值给变量被提前

所以,实际情况是:

1
2
3
4
5
6
7
8
9
10
11
12
13
function foo() {
alert('foo');
}

var bar;

foo();

bar();

bar = function () {
alert('bar');
};

最后,为了避免被语言所坑,大家最好都是先声明在调用吧,能减少不必要的Debug时间。