变量提升与作用域
一、什么是作用域?
作用域一般分为两种:
(a)块级作用域
任何一对花括号({和})中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域。
(b)函数作用域
定义在函数中的参数和变量在函数外部是不可见的。我们称之为函数作用域.
大多数语言都分为这两种作用域,如C++,但JavaScript没有块级作用域!如下
for(var i=0;i<3;i++){ console.log(i);// 0 1 2 } alert(i);//3 在{}内定义的变量在{}外也能访问到了!
但是我们可以模拟块级作用域,基于JavaScript变量销毁(函数被执行完后,其内部变量便被销毁)的理论。如下:
function test(){ (function (){ for(var i=0;i<4;i++){ } })(); alert(i); } test();//undefined
for语句块放到了一个闭包之中,然后调用这个函数,当函数调用完毕,变量i自动销毁,因此,我们在块外便无法访问了。
所以闭包可以用来防止变量污染。
二、变量提升
JavaScript只支持函数作用域,而且在一个函数中的任何位置定义的变量在该函数中的任何地方都是可见的(因为变量被提升了)。
在javascript,变量有4种基本方式进入作用域:
1 语言内置:所有的作用域里都有this和arguments;(译者注:经过测试arguments在全局作用域是不可见的)
2 形式参数:函数的形式参数会作为函数体作用域的一部分;
3 函数声明:像这种形式:
function foo(){}
4 变量声明:像这样:
var foo;
变量提升是说:
变量声明会被提升(变量赋值不会被提升),函数声明会连着函数体一起被提升。且函数声明比变量声明具有更高的优先级
例子如下:
function fn(){ if(x){ console.log(x); (typeof x == 'function') && x(); } return; var x =1; function x(){ alert('x'); } var x = function(){ alert('x2'); } } fn();//function x(){alert('x');} //x 函数声明连着函数体一起被提升 函数声明比变量声明具有更高的优先级
function fn(){ if(x){ console.log(x); } return; var x =1; var x = function(){ alert('x2'); } } fn();//undefined 变量声明或者函数表达式只会提升声明
function fn(){ var x =1; var x = function(){ alert('x2'); } if(x){ console.log(x); } return; } fn();//function x(){alert('x2');} 后定义的覆盖先定义的
function fn(){ var x = function(){ alert('x2'); } var x =1; if(x){ console.log(x); } return; } fn();//1 后定义的覆盖先定义的
foo(); // foo is not a function bar(); // bar baz(); // baz is not a function spam(); // spam is not defined?? var foo = function () {alert('foo');}; function bar() {alert('bar');}; var baz = function spam() {alert('spam');}; foo(); //foo bar(); // bar baz(); // spam? spam(); //spam is not defined ?
看到上面的结果,你有哪些疑问?我主要是在spam()的执行上有疑问。
alert(a); //a is not defined a=1;
没有被var 声明,变量不会提升。
参考文章:
1.JavaScript的作用域和块级作用域概念理解