在es5中,js是没有块级作用域的,只有函数作用域,而且函数作用域是链式的,内层函数可以访问到外层函数中的变量,外层函数是访问不到内层函数中的变量的,在es6中,新增了let和const命令,使得js拥有了块级作用域,不再需要使用函数来模拟块级作用域,下面来通过几个例子来分析一下js中的作用域问题。
一.函数作用域分析
1.函数的链式作用域分析
function add() {
color = "aa";
}
console.log(color);
在上面这段代码中,color能否被打印出?答案是不能的,因为函数未被执行,color未进入内存中,必须在打印color之前调用这个函数,color才可以被打印出。
function add() {
var color = "aa";
}
add();
console.log(color);
在这段代码中,color仍然无法被打印,因为var定义了一个局部变量,在函数执行后,color就被销毁。
function add() {
color = "aa";
}
add();
console.log(color);
这段代码中,color可以被正确打印出,但并不推荐这种不声明变量直接赋值的写法,这在严格模式中会报错。
但我们在很多时候需要在外层函数中访问内层函数中的变量,这时候我们就用到了闭包,来看一个最简单的例子。
function A(){
a=123;
function B(){
return a;
}
return B;
}
A();// 123
看似和直接执行A函数效果一样,但其实我们是使用了A函数中嵌套的B函数来获取到了a,这个函数并没有实际作用,但当将A作为构造函数,B为A函数的对象方法时,a就成为了私有属性。
二. 块级作用域分析
1.es5中无块级作用域带来的影响
var a = [ ];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[1]();
首先我们来看上面的例子,运行这段代码的结果是10,有很多人会问为什么是10呢,这就是没有块级作用域所带来的影响,调用a[1]时,会运行console.log(i),这其中的i是哪个i呢?是当初循环定义中的那个i吗?不是的,因为没有块级作用域导致内存泄漏,这里i的值是for循环结束后的值,也就是10,不管运行a[]中的哪一个,结果都是10.
为了避免产生内存泄漏,在es5中我们常用函数来模拟块级作用域,来看下面这个例子。
var gg=[];
for (var x = 0; x < 10; x++) {
gg[x] = function (num) {
return function(){
console.log(num);
};
}(x);
}
gg[1]();
在这个例子中,我们使用立即执行函数来模拟块级作用域来让函数能够正常运行。
2.在es6中增加了let和const命令,使得js拥有了块级作用域,上面示例中的代码可以像下面这样写。