JS没有块级作用域,理解起来可能有点困难。先看下面这个例子:
if (true) {
var color = 'blue'
}
console.log(color) //'blue'
这里是在一个if语句中定义了变量color,如果是在C、C++或Java中,color会在if语句执行完毕后被销毁。但在JS中,if语句中的变量声明会将变量添加到当前的执行环境(这里是全局变量)中。再看看在for语句中:
var a = 0
for (var i = 0; i < 10; i++) {
a += i
}
console.log(i)
1、声明变量
使用var声明的变量会自动被添加到最接近的环境中。在函数内部,最接近的环境就是函数的局部环境;在with语句中,最接近的环境是函数环境。如果初始化变量时没有使用var声明,该变量会自动被添加到全局环境。
function add (num1, num2) {
var sum = num1 + num2
return sum
}
var result = add(10, 20) //30
console.log(sum) //会报错
若省略该例子中的var关键字,sum将被添加到全局变量:
function add (num1, num2) {
sum = num1 + num2
return sum
}
var result = add(10, 20) //30
console.log(sum) //30
2、查询标识符
当在某个环境中为了读取或写入而引用一个标识符时,必须通过搜索来确定该标识符实际代表什么。搜索过程从作用域链的前端开始,向上逐级查询与给定名字匹配的标识符。如果在局部环境中找到了该标识符,搜索过程停止。如果在局部环境中没有找到该变量,则继续沿作用域链向上搜索。搜索过程将一直追溯到全局环境的变量对象。若在全局环境中也没有找到这个标识符,则意味着该变量尚未声明。
看下面两个例子:
var color = 'blue'
function getColor () {
return color
}
console.log(getColor()) //'blue'
var color = 'blue'
function getColor () {
var color = 'red'
return color
}
console.log(getColor()) //'red'
总结:
1、离开作用域的值将被自动标记为可以回收,因此将在垃圾收集期间被删除。
2、“标记清除”是目前主流的垃圾收集算法,这种算法的思想是给当前不使用的值加上标记,然后再回收其内存。
3、另一种垃圾收集算法是“引用计数”,这种算法的思想是跟踪记录所有值被引用的次数。JS引擎目前都不再使用这种算法;但在IE中访问非原生JS对象时,这种算法仍然可能会存在问题。