JavaScript作用域体会
先来看看MDN上对作用域的描述:
当前的执行上下文。值和表达式在其中 “可见” 或可被访问到的上下文。如果一个变量或者其他表达式不 “在当前的作用域中”,那么它就是不可用的。
从字面上看,“作用域”就是变量起作用的范围。那“作用域”的存在对我们写代码有什么作用呢?
程序的执行是要占用内存的,我们定义的变量是在内存中开辟空间来存放的,在程序执行完毕之前,如果不进行垃圾回收,那已经用不上的变量在内存中仍然会占据空间,如果程序特别大,那随着程序运行,它所占用的内存也会越来越大,这里暂时不讨论是否限定了程序的最大占用内存。
因此垃圾回收机制就非常有必要了,当一个变量在程序中某个地方之后再也用不到,那就应该被回收掉,那怎么确定变量“再也用不到了”?
当当当当,作用域的概念不就用上了。我们规定了作用域的概念,比如用一些特殊的标记(比如大括号{})来划定一个范围,如果一个变量是在该范围内声明的,它的作用域就是这个划定的范围。
当程序进入到该范围进行执行,所声明的变量就会被垃圾回收器标记为该作用域的变量,当程序执行完该范围内的代码,并跳出该范围去执行其他代码后,垃圾回收器就认为该范围中定义的变量已经“没有作用”了,进而将其回收处理。
这当然只是我的看法啦,如果有什么错误的地方请大胆指正。
下面就来看看一些有趣的东西。
我们猜猜看下面代码执行结果是什么样的:
var a = 100;
(function(){
console.log(a);
a = 5;
console.log(window.a);
var a = 200;
console.log(a);
})();
结果是:undefined 、100 、 200
按照规范,var a = 10定义了一个全局变量 a ,那第一个console.log(a)应该打印100才对,但是却是未定义,这是为什么呢?
再来看下面代码:
var a = 100;
(function(){
console.log(a);
a = 5;
console.log(window.a);
// var a = 200;
console.log(a);
})();
这里,我们把函数内对变量a 的声明注释掉,再来执行,输出结果是:
100 、 5 、 200
显然,这次我们又能访问到全局的变量a了。为啥?
俗气点说,应该是在程序开始执行前,会对代码进行一遍扫描,看看哪里定义了变量,然后会把声明隐式放到当前作用域的最前面,也就是说 var a = 20 被拆成了两部分,即 var a, a = 20, 其中 var a 会放到函数作用域的最前面,因此第一次的代码应该是这样子的:
var a = 100;
(function(){
var a
console.log(a);
a = 5;
console.log(window.a);
a = 200;
console.log(a);
})();
局部变量比全局变量优先级别高,当没有明确指出a是全局的还是局部的,优先认为是局部变量。
这样,第一次打印的时候没有对 a 赋值,因此打印出了undefined,第二次打印的时候虽然已经赋值为 a = 5 , 但是打印的是window对象的 a , 按照规范,显然是可以访问到的,因此是全局变量 a 被打印出来。而第三次打印的 a 是200,优先取了局部变量 a 进行操作。
…