javascript学习笔记(二)-闭包
2016-10-28 11:40
232 查看
闭包的理解和使用是学习js绕不过去的一道坎,为此笔者在阅读《javascript权威指南》的基础上又参考了几篇博客,终于了解个大概,下面就来和大家分享分享。
参考资料:
《javascript权威指南 第6版》
学习javascript闭包 - 阮一峰
MDN - JavaScript闭包
全局变量有全局作用域,一经定义就可在任何位置使用。这和静态语言的全局变量有些相似。而局部变量就有些特殊,不同于静态语言(如java、C)的
也就是说,只要在一个函数体内定义的局部变量,在整个函数内都是有效的。所以上面例子中,内函数可以读取到外函数的变量,for循环结束后的变量还可以被读取。因为它们都属于同一个函数作用域(test()函数)内。
好了,现在思考这个问题。在内函数
因为我们的inner()也是一个函数,正是由于函数作用域的存在,函数外的语句不能访问函数内的变量。所以到现在我们可以得知
javascript具有函数作用域
在嵌套函数中,嵌套函数可以访问外函数的变量
最简单的例子,我们想在函数外读取
内函数可以读取局部变量,于是
到此就解决了,可我们还有不满。现在是返回一个值,要是多个值呢?返回数组又不方便,还有没有别的方法?现在想,既然js可把函数当做返回值,能不能将内函数返回?
可行,至于为什么test()函数的局部变量
刚才说,要是函数内有多个局部变量,而要都在函数外访问怎么办?可以这样
这种写法有点眼熟,对了,在静态语言中(java、C#)读取类内的私有变量不和这很类似吗,在类里有get、set方法。类外调这些方法。不过在js中是读取函数内局部变量。
闭包是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。
可以看出,闭包是一类函数,它能读取创建它时的局部变量(在js中就是内函数能读取外函数的局部变量),这不算稀奇,而稀奇的是,即使它离开了这个环境,它依然保存着这个变量。意味着,这个闭包保存了这些创建时引用的局部变量。
上面解释的很清楚了,让我们再复杂一点,试着往闭包传参数。
总之,闭包就是访问了它的外部变量的函数,可以用它来模拟私有方法,封装局部变量等。至于其他的特性及原理日后有机会再研究。
参考资料:
《javascript权威指南 第6版》
学习javascript闭包 - 阮一峰
MDN - JavaScript闭包
1. 变量作用域
要理解js中的闭包,就必须了解js的变量作用域。js的作用域有2种,全局变量和局部变量。全局变量有全局作用域,一经定义就可在任何位置使用。这和静态语言的全局变量有些相似。而局部变量就有些特殊,不同于静态语言(如java、C)的
{}作用域,javascript的作用域是函数范围的。
function test(){ //因为函数体内有定义a的地方,只是目前还未赋值, //所以是undefined。 console.log(a); //undefined for (var i = 0; i < 5; i++) { console.log(i); //0,1,2,3,4 var j=i; } var a = 1; //由于js特殊的函数作用域,在for循环内部定义的 //i、j在循环结束后并没有销毁而是保存下来了 console.log('i='+i); // i=5 console.log('j='+j); // j=4 function inner(){ var inner1 = 123; //内函数的一个变量 // 特殊的函数作用域使得内部函数可以读取外部函数变量 console.log('a='+a); console.log('i='+i); } inner(); // 输出 a=1 ,i=5 //console.log(inner1); } test();
也就是说,只要在一个函数体内定义的局部变量,在整个函数内都是有效的。所以上面例子中,内函数可以读取到外函数的变量,for循环结束后的变量还可以被读取。因为它们都属于同一个函数作用域(test()函数)内。
好了,现在思考这个问题。在内函数
inner()定义的
inner1这个变量外函数是否可以读取呢?答案是不能的。为什么,不是说函数内的变量都可以读取吗?
因为我们的inner()也是一个函数,正是由于函数作用域的存在,函数外的语句不能访问函数内的变量。所以到现在我们可以得知
javascript具有函数作用域
在嵌套函数中,嵌套函数可以访问外函数的变量
2.读取局部变量
上面我们说函数外是读取不到函数内定义的局部变量的。那我们有这个需求怎么办?最简单的例子,我们想在函数外读取
test()函数的
i变量
function test(){ var i=0; } // 在此输出i的值
内函数可以读取局部变量,于是
function test(){ var i=0; function inner(){ return i; //在内函数读取到了i值,并作为返回值返回 } return inner(); } console.log(test()); // 0
到此就解决了,可我们还有不满。现在是返回一个值,要是多个值呢?返回数组又不方便,还有没有别的方法?现在想,既然js可把函数当做返回值,能不能将内函数返回?
function test(){ var i=0; function inner(){ return i; } return inner; //返回一个函数 } var a = test(); //a是一个函数 console.log(a()); // 0
可行,至于为什么test()函数的局部变量
i没有在test()执行完销毁而在调用a()时还能打印出来,这是下一篇深入闭包原理时讲的内容。现在我们先关注现象。
刚才说,要是函数内有多个局部变量,而要都在函数外访问怎么办?可以这样
function test() { var v1 = 'v1的值'; var v2 = 'v2的值'; function funcV1() { return v1; } function funcV2(){ return v2; } return { //返回一个对象,并将内函数当做值传入 v1:funcV1, v2:funcV2 } } var obj = test(); //接收对象值 console.log(obj.v1()); //v1的值 console.log(obj.v2()); //v2的值
这种写法有点眼熟,对了,在静态语言中(java、C#)读取类内的私有变量不和这很类似吗,在类里有get、set方法。类外调这些方法。不过在js中是读取函数内局部变量。
3.闭包
闭包广泛存在于函数式编程的语言中,维基百科上对闭包的定义是:闭包是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。
可以看出,闭包是一类函数,它能读取创建它时的局部变量(在js中就是内函数能读取外函数的局部变量),这不算稀奇,而稀奇的是,即使它离开了这个环境,它依然保存着这个变量。意味着,这个闭包保存了这些创建时引用的局部变量。
function test(){ var v1 = 1; return function(){ //返回匿名的内函数 v1++; return v1; } } var f = test(); //现在f就是一个闭包函数,由于创建时引用了v1这个局部变量,现在它保存着这个变量 /** * 每次调用,v1值加1 */ console.log(f()); //2 console.log(f()); //3 console.log(f()); //4
上面解释的很清楚了,让我们再复杂一点,试着往闭包传参数。
function test(){ return function(a){ a.a1++; } } var a ={ a1:1 } var f = test(); //传入一个对象a f(a); f(a); f(a); //对象在闭包中被改变 console.log(a); // { a1: 4 }
总之,闭包就是访问了它的外部变量的函数,可以用它来模拟私有方法,封装局部变量等。至于其他的特性及原理日后有机会再研究。
相关文章推荐
- JavaScript学习笔记(6)---闭包
- JavaScript 闭包学习笔记
- JavaScript学习笔记十四:闭包
- Javascript学习笔记:闭包题解(2)
- 韩顺平_轻松搞定网页设计(html+css+javascript)_第33讲_Object类_闭包_成员函数再说明_聪明的猪小练习_学习笔记_源代码图解_PPT文档整理
- JavaScript中闭包的学习笔记
- JS学习笔记:JavaScript匿名函数与闭包(closure)
- Javascript学习笔记——闭包
- 零基础入门-javascript学习笔记之传说中的闭包
- JavaScript 学习笔记七 闭包二
- JavaScript学习笔记4-闭包
- JavaScript 学习笔记— —闭包(一)
- javascript 学习笔记(3) 闭包
- JavaScript学习笔记(九)—— JS 理解闭包
- Javascript学习笔记--理解闭包
- javascript学习笔记(十三) js闭包(转)
- JavaScript权威设计--命名空间,函数,闭包(简要学习笔记十二)
- Javascript学习笔记:闭包题解(3)
- Javascript学习笔记:闭包题解(1)