您的位置:首页 > Web前端 > JavaScript

深入理解Javascript的var变量和闭包

2015-02-01 23:13 405 查看
今天无意间看到阮一峰写的一个关于ES6新特性let。let的出现,就是为了弥补var的不足。由此,写下这篇博客重新回顾一下Javascript老生常谈的闭包和它的一个作用域的诟病。

闭包的概念我就不说了,很多书上都又说明和解释,就是在一个函数内部可以访问函数外的上下文。今天重点来说以下var变量。因为平时开发的时候,如果不对这个关键字有一个很深刻的认识,很容易产生很多坑和错觉。

本文要阐明的观点是:由var定义的变量,它作用域在一个函数体内,而不是我们其他语言理解的大括号{ }内。

下面又几个经典的小例子:

(function(){
var a = [];
for (var i = 0; i < 10; i++) {
var c = i;
a[i] = function () {
console.log(c);
};
}
a[6](); // 9

})()


这个例子稍微有点Javascript基础的人估计都知道,这也是《Javascript Good Parts》里头特别说明过的一个例子。该例子中输出的c是9而不是6。

解释:首先,在函数a[6]中,是可以访问到变量c的,而且,在执行a[6]函数前,此时c的值已经是9了。

没理解我说的?或者说我已经理解了上面那个例子了?好,没关系,再来看下面这个例子:

(function(){
if(true){
var a=10;
}
console.log(a); //输出10 而不是undefined
})();


在上面这个例子中,输出结果是什么?学过java或其他成熟的面向对象语言的人都可能会以为输出的是undefined。但是,让你们失望了,输出结果真的是10。

不理解?这个时候回顾一下我一开始说的:“由var定义的变量,它作用域在一个函数体内,而不是我们其他语言理解的大括号{ }内。”,是不是明朗了很多?

同样的,下面的这个例子中,输出的是10,而不是5:

function f1() {
var n = 5;
if (true) {
var n = 10;
}
console.log(n); // 5
}


这也就是为什么ES6新特性中有个let关键字。let的作用域是块级的(而不是函数级的),跟我们传统理解的其他语言的作用域是一样的。

好了,理解了之后来做个小练习吧:

(function(){
var n=1;
var arr=[];
var arr2=[];
for(var i=0;i<10;i++){
var c=i;
arr[i]=function(){
for(var j=0;j<4;j++){
c=c+10;
arr2[j]=function(){
console.log(c);
}
}
return c;
}
}
//console.log(‘c:'+c); //c=9
console.log(arr[6]());  //c=49
//console.log('c:'+c); //c=49
arr2[3]();//c=49
})();


上面两个地方c的输出结果可以理解了吗?其实个人认为这是Javascript中的一个大坑。没有彻底明白的人很容易迷糊。

另外,可以参见阮一峰大神的 var && let:

http://es6.ruanyifeng.com/#docs/let
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: