JavaScript作用域以及闭包(一)

第二篇链接 JavaScript作用域以及闭包(二)

JavaScript作用域

在学习JavaScript的过程中不可避免会遇到闭包问题,其实闭包概念并不难理解,只要理解了JavaScript中作用域概念,那么就很容易理解什么是闭包了。

JavaScript没有块级作用域

//没有块级作用域
if(true){
var sm = "hello";
}

console.log(sm); //hello

 

JavaScript的作用域是由函数"决定"的,JavaScript的执行环境只有两种——全局和局部(函数)。

作用域链,在JavaScript中标识符的解析是沿着作用域一级级地搜索标识符的过程。搜索过程始终以作用域链的前端开始,然后逐级向后回溯,直到找到标识符(找不到通常会报错)

//作用域链搜索
var name = "json";
(function(){
console.log(name); //undefined
var name = "hello";
})();

 

这个例子之所以输出的是'undefined'是因为JavaScript的作用域链机制,在执行console语句时,首先会搜索匿名函数内部的作用域,而且恰好找到了name("hello")这个变量,所以外层的name变量被屏蔽了。但执行到console语句时,name还没被定义(或者说是初始化),所以得到的是undefined值。

闭包

那么明白了JavaScript的作用域概念后,所谓的闭包也就不难理解了。通俗地讲JavaScript中每个函数都是闭包(上下文环境:全局),但通常嵌套的函数更能体现闭包特性。下面简单说明下:

按JavaScript作用域链的机制,被嵌套在里面的函数(简称:里函数)是可以访问到其外部的函数(外函数)的变量的。这个很容易理解。而闭包就是,在返回里函数的时候,不仅会返回函数本身还会把函数的上下文环境一并返回。这就是闭包的本质。

//引用自'JavaScript语言精粹'
var quo = function(status){
return {
get_status:function(){
return status;
}
};
};

var myQuo = quo("amazed");

console.log(myQuo.get_status()); //amazed

 

"即使quo已经返回了,但get_status方法依然享有访问quo对象status属性的特权。get_status方法并不是访问该参数的一个副本,它访问的就是该参数本身。这是可能的,因为该函数可以访问它被创建时所处的上下文环境。这被称为闭包"

  

下面这段代码比上面那段更为通俗,通过下面的例子对闭包可以有进一步的理解:

//引用自'nodejs开发指南'
var smClosure = function(){
var count = 0;
var get = function(){
count++;
return count;
};
return get;
}

var sm1 = smClosure();
var sm2 = smClosure();
console.log(sm1()); //1
console.log(sm2()); //1
console.log(sm1()); //2
console.log(sm1()); //3
console.log(sm2()); //2

 

sm1,sm2分别调用了smClosure()函数,生成了两个闭包实例,他们内部引用的count分别属于各自的执行环境。这就是所谓的返回内部函数时,不仅会返回函数本身还会一并返回其上下文环境的意思。

扩展:

关于作用域,JavaScript的变量和函数声明都会被存储到执行上下文的变量对象中,即声明提升。函数声明的优先级高于变量声明的优先级,但不会覆盖变量赋值。

而命名函数表达式的标识符(即函数名)在外部作用域是无效的,只在函数作用域内有效。

var sm = function something(){
console.log(typeof something); //function
}
sm();
console.log(typeof something); //undefined
console.log(typeof sm); //function

参考

《JavaScript高级程序设计》

《JavaScript语言精粹》

《nodejs开发指南》

posted @ 2015-09-27 09:52  hwencc  阅读(344)  评论(0编辑  收藏  举报