京东面试题,面试官小姐姐给出了一道题:
var a = 100;
function test(){
console.log(a);
a = 10;
console.log(a);
console.log(this.a);
var a;
}
test();
问我这三个会打印出来的值是什么?
好吧我这个还以为是要考我闭包的问题,后来一想是个变量提升的问题(好吧好吧,是小姐姐看我太尴尬了,就给我讲了一下)
回来研究一下这个变量的作用域和变量提升:
一、作用域:
一个变量的作用域(scope)是程序源代码中定义这个变量的区域。
全局变量拥有全局作用域,在javaScript代码中任何地方都有定义的。
然而在函数内声明的变量只是在函数内部有定义,他们是局部变量,作用域也只是在局部。
在函数体内,局部变量的优先级要高于全局变量。如果在函数体内重新声明一个与局部变量重名的变量,局部变量就会覆盖全局变量的值。
来看个例子:
var num="100";
function scope(){
var num="10";
function innerScope(){
var num = "1";
console.log(scope);//输出:1
}
innerScope();
console.log(num);//输出:10
}
scope();
console.log(num);//输出:100
这个例子会打印三个数,分别是1,10,100;
局部变量的作用域仅仅在函数内部,出了函数体之后,局部变量就会被销毁。
在innerScope()函数中,虽然又声明了一个num,但是innerScope()中的num是局部变量,只是与全局变量的名字相同,并不是全局变量,所以,虽然在该函数中把num赋值为1,但这仅仅是一个与全局变量名称相同的一个变量而已,并没有改变全局变量的值。
再来看一个例子:
var num="100";
function scope(){
var num="10";
function innerScope(){
num = "1";
console.log(scope);//输出:1
}
innerScope();
console.log(num);//输出:1
}
scope();
console.log(num);//输出:100
上面这部分代码中,在innerScope()函数中,我们并没有用var来声明num,所以,在这里的num的作用域就被提升了,即我们将scope中的num的值重置了,所以在输出的时候输出的结果为嵌套作用域内的局部变量。
二、变量提升
在Javascript中,函数及变量的声明都将被提升到函数的最顶部。
在js中,变量的声明会被解析器悄悄的提升到方法体的最顶部,但是需要注意的是,提升的仅仅是变量的声明,变量的赋值并不会被提升,我们需要注意的是,函数的声明与变量的声明是不一样的。函数的函数体也会被一起提升。
函数表达式和变量表达式只是其声明被提升,函数声明是函数的声明和实现都被提升。
所以上面那个题就很好理解了。
我们再来看一下这个题:
var num="100";
function scope(){
var num="10";
function innerScope(){
var num = "1";
console.log(scope);//输出:1
}
innerScope();
console.log(num);//输出:10
}
scope();
console.log(num);//输出:100
- 因为变量提升,a提升到最前面,声明未赋值,所以第一个就会打印undefined;
- 第二个在a声明之后,而且a赋值为10,所以第二个打印出来10;
- 第三个,因为test()是在window下调用的;this指的是test()调用的作用域,所以第三个打印100;
看一个函数提升的例子:
<script language="javascript" type="text/javascript">
//在全局对象中声明两个全局函数,反模式
function foo()
{
alert("global foo");
}
function bar()
{
alert("global bar");
}
//定义全局变量
var v = "global var";
function hoistMe()
{
alert(typeof foo); //function
alert(typeof bar); //undefined
alert(v); //undefined
//为什么bar函数和变量v是未定义而不是全局变量中定义的相应的函数变量呢?
//因为函数里面定义了同名的函数和变量,无论在函数的任何位置定义这些函数和
//和变量,它们都将被提升到函数的最顶部。
foo(); //local foo
bar(); //报错,TypeError "bar is not a function"
//函数声明,变量foo以及其实现被提升到hoistMe函数顶部
function foo()
{
alert("local foo");
}
//函数表达式,仅变量bar被提升到函数顶部,实现没有被提升
var bar = function()
{
alert("local bar");
};
//定义局部变量
var v = "local";
}
(function()
{
hoistMe();
})();
//函数表达式和变量表达式只是其声明被提升,函数声明是函数的声明和实现都被提升。
/**由于函数提升的效果,hoistMe方法相当于
function hoistMe()
{
//函数声明,变量foo以及其实现被提升到hoistMe函数顶部
function foo()
{
alert("local foo");
}
//函数表达式,仅变量bar被提升到函数顶部,实现没有被提升(同变量提升)
var bar = undefined;
//变量声明被提升
var v = undefined;
alert(typeof foo); //function
alert(typeof bar); //undefined
alert(v); //undefined
foo(); //local foo
bar(); //报错,缺少对象
bar = function()
{
alert("local bar");
};
v = "local";
}
*/
</script>