理解javascript中变量和函数的挂起 hoisting

今天给大家分享一篇文章,原文地址:http://jamesallardice.com/explaining-function-and-variable-hoisting-in-javascript/

javascript的域机制(scoping mechanism)是这门语言最难懂的地方之一,如果你不能完全理解他,你就会遇到很多困难。而理解域机制的钥匙就是理解挂起概念 ( the concept of hoisting)

直接看下面的例子:

var x = 10;

function y() {

console.log(x); //Prints undefined

var x = 20;

console.log(x); //Prints 20

}

y();

console.log(x); //Prints 10

如果你理解最基本的域机制,你应该清楚,function y 可以访问到第一行声明的x 根据这个逻辑,由于我们给x赋值10,所以很容易想到第一个console.log 的结果应该是10 而不是undefined

这是由于function y中的第二行影响了结果,如果你去掉第二行(var x=20) 第一个console.log 的结果就是10了。 那么这是为什么呢???这叫要说到javascript中的挂起hoisting , 上面的例子其实可以这么理解:

var x; //x声明被挂起 (x is undefined)

x = 10; //赋值 (x is 10)

function y() {

var x; //声明另一个也叫x的变量,被挂起(x is undefined)

console.log(x); //打印 undefined

x = 20; //赋值(x is 20)

console.log(x); //打印 20

}

y();

console.log(x); //变量x在外边的域还是10

这个简单的例子可以充分证明挂起的概念在变量定义中的作用,有2点要记住:

首先,我们在第一个例子中看到的奇怪现象是因为恰好有个同名的变量x , 第二个x的调用发生在赋值之前了。

其次,声明本身被挂起了,而赋值会在我们写下的同时发生作用。

同理,function的声明也会被挂起在他被定义的那个域中。

sayHello(); //调用发生在声明之前

function sayHello() {

console.log("Hi!");

}

根据挂起理论:由于函数声明被域挂起了,所以在他之前的调用是有效的。

再看一个函数表达式的例子

sayHello(); // TypeError, undefined is not a function!

var sayHello = function() {

console.log("Hi!");

};

由于函数表达式是一个变量声明和赋值操作,所以变量被挂起了,但由于赋值发生在调用之后。

调用sayHello()时候该变量sayHello还不是一个function ,所以发生了类型错误。