函数作用域和声明提前
《JavaScript权威指南》P57
函数作用域(function scope):变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。
function test() { var i = 0; //i在整个函数体内均有定义 if (typeof o == 'object') { var j = 0; //j在整个函数体内均有定义,不仅仅是在这个代码段内 for (var k = 0; k < 10; k++) { //k在整个函数体内均有定义,不仅仅是在循环内 console.log(k); //输出数字0-9 } console.log(k); //k已经定义了,输出10 } console.log(j); //j已经定义了,但可能没有初始化 }
JavaScript的函数作用域是指在函数内声明的所有变量在函数体内始终是可见的。JavaScript这个特性被称为声明提前(hoisting),即JavaScript函数里声明的所有变量(但不涉及赋值)都被“提前”至函数体的顶部。
示例代码:
var scope="global"; function f(){ console.log(scope); //控制台中打印结果是什么? var scope='local'; console.log(scope);//控制台中打印结果是什么? } f();
打印结果:
代码解析过程:
var scope="global"; function f(){ console.log(scope); //输出'undefined',而不是'global' var scope='local'; //变量在这里赋初始值,但变量本身在函数体内任何地方均是有定义的 console.log(scope);//输出'local' }
你可能会误以为函数的第一行会输出"global",因为代码还有执行到var 语句声明局部变量的地方。其实不然,由于函数作用域的特性,局部变量在整个函数体始终是有定义的,也就是说,在函数体局部变量遮盖了同名全局变量。尽管如此,只有在程序执行到var语句的时候,局部变量才会被真正赋值。因此,上述过程等价于:将函数的变量声明“提前”至函数体顶部,同时变量初始化留在原来的位置:
var scope = "global"; function f() { var scope; //在函数顶部声明了局部变量 console.log(scope); //变量存在,但其值是'undefined' scope = 'local'; //这里将其初始化并赋值 console.log(scope);//这里它具有了我们所期望的值 } f();