【JavaScript 从零开始】变量作用域
变量作用域
一个变量的作用域(scope)是程序源代码中定义这个变量的区域。
全局变量拥有全局作用域,在JavaScript代码中的任何地方都是有定义的。然而在函数内声明的变量只是函数体内有定义。
他们是局部变量,作用域是局部性的。函数参数也是局部变量,它们只是函数体内有定义。
在函数体内,局部变量的优先级高于同名的全局变量。
如果在函数内声明的一个局部变量或者函数参数中带有的变量和全局变量重名,那么全局变量就被局部变量所遮盖。
var scope ="global"; //声明一个全局变量 function checkscope() { var scope ="local"; //声明一个同名的局部变量 return scope; //返回局部变量的值,而不是全局变量的值 } checkscope() //=> "local"
尽管在全局作用域编写代码是可以不写var 语句,但声明局部变量是则必须使用var语句。
如果在申明局部变量是不使用 var :
scope="global"; //声明一个全局变量,甚至不用var来声明 function checkscope2() { scope="local"; //糟糕!我们刚刚修改全局变量 myscope="local"; //这里显示地声明了一个新的全局变量 return [scope,myscope]; //返回两个值 } checkcope2(); //=>["local","local"] : scope; //=>"local" : 全局变量修改了 myscope; //=>"local" : myscope成为了全局变量
函数作用域和声明提前(置顶解析)
在一些类似C语言的编程语言中,花括号内的每一段代码都具有各自的作用域,而且变量在声明它们的代码段之外是不可见的,我们称之为块级作用域(block scope),
而JavaScript 中没有块级作用域。JavaScript取而代之的使用了函数作用域(function scope):变量在声明它们的函数体内以及这个函数体嵌套的任意函数体内都是有定义的。
如下代码:
function test(o) { var i = 0; // i 在整个函数test内都是有定义的 if ( typeof o =="object") { var j = 0; // j 在函数test内都是有定义的 for ( var k=0; k < 10; k++ ) // K 在函数test内都是有定义的 不仅仅是在循环内 { console.log( k ); // 输出数字0~9 } console.log(k); // k 已经定义了,输出10 } console(j); //j 已经定义了,输出 undefined 或0 }
JavaScript 的函数作用域是指 在函数内声明的所有变量在函数体内始终是可见的。
有意思的是,这意味着变量在声明之前甚至已经可用了。
JavaScript 的这个特性呗非正式的称为 声明提前 (hoisting) ---------我喜欢称为 置顶解析
即JavaScript 函数里声明的所有变量(不涉及赋值)都被“提前” 值函数体的顶部,看一下如下代码:
var scope ="global"; function f () { console.log(scope); //输出 “undefined ” 而不是 “global” var scope = "local"; //变量在这里赋值,但是变量在 f 函数顶部已经有定义了 console.log(scope); //输出 “local" }
其实上面代码可以这样理解
var scope ="global"; function f () { var scope ; //在函数顶部声明可局部变量 scope console.log(scope); //输出 “undefined ” 而不是 “global” scope = "local"; //变量在这里赋值 console.log(scope); //输出 “local" 这里有了我们期望的值 }
作为属性的变量(隐式全局变量)
当声明一个JavaScript 全局变量时,实际上是定义了全局对象的一个属性。
当使用var 声明一个变量时,创建的这个属性是不可配置的,也就是说这个变量无法通过 delete 运算符删除。
隐式全局变量和明确定义的全局变量间有些小的差异,就是通过delete
操作符让变量未定义的能力。
- 通过var创建的全局变量(任何函数之外的程序中创建)是不能被删除的。
- 无var创建的隐式全局变量(无视是否在函数中创建)是能被删除的。
这表明,在技术上,隐式全局变量并不是真正的全局变量,但它们是全局对象的属性。属性是可以通过delete
操作符删除的,而变量是不能的:
// 定义三个全局变量 var global_var = 1; global_novar = 2; // 反面教材 (function () { global_fromfunc = 3; // 反面教材 }()); // 试图删除 delete global_var; // false delete global_novar; // true delete global_fromfunc; // true // 测试该删除 typeof global_var; // "number" typeof global_novar; // "undefined" typeof global_fromfunc; // "undefined"