昨天在看思否时,发现了一篇文章是关于JavaScript如何实现重载的,由于以前也和学长讨论过JavaScript是否能够重载,就点进去看了看,发现里面的两个方法的其中一个需要用闭包实现,就看了几篇博客学习了一下,顺便写篇博客加深一下印象。
(JavaScript重载的文章在这:https://segmentfault.com/a/11...)
什么是闭包
- 闭包的本质是一个函数
- 闭包可以访问函数内部变量
- 闭包的存在会使内部变量保留在内存中
这个可以说是闭包比较容易让人理解又比较全面的解释了,更通俗一些:当function里嵌套function时,内部的function可以访问外部function里的变量。
下面让我们来看一个例子:
function A(){
function B(){
console.log('Hello Closure!');
}
return B;
}
var C = A();
C();// Hello Closure!
上面就是一个最简单的闭包。
就下来让我们来看一下下面这个函数,他是不是一个闭包呢?
function foo(x) {
var tmp = 3;
function bar(y) {
alert(x + y + (++tmp));
}
bar(10);
}
foo(2);
答案是:并不是,重新看一下闭包的定义,就明白了:
它能吗?明显不能,当你return的是内部function时,就是一个闭包。
function foo(x) {
var tmp = 3;
return function (y) {
alert(x + y + (++tmp));
}
}
var bar = foo(2); // bar 现在是一个闭包
bar(10);
至于能保存的原因,看了看网友的解释:
由于内部函数嵌套在foo中,导致内部函数的作用域链上添加了foo的作用域;而当内部函数被返回后,也要保证其作用域链有效,因此,函数foo的作用域不得不被保留在内存中以供内部函数访问。
闭包的作用
接下来来谈谈闭包的作用,初学者刚接触时肯定是一脸懵逼,闭包的用处究竟是什么,下面就来谈一谈。
一.模仿块级区域
首先简单举个例子来,解释一下什么是块级作用域:
function A(num) {
for (var i = 0; i < num; i++) {
num++;
}
console.log(i)
}
在这个简单的函数中,变量i是在for循环中定义的,如果是在C++或者Java中,这样定义的变量,一旦循环结束,变量也就随之销毁,i的作用范围只在循环这个小块,就称为块级作用域。在javascript中,没有这样的块级作用域,前面一篇文章已经提到,变量是定义在函数的活动对象中的,因此,从定义i开始,在函数内部可以随时访问它。
这样的坏处显而易见:由于javascript不会告诉你变量是否已经被声明,容易造成命名冲突,如果是在全局环境定义的变量,就会污染全局环境,因此可以利用闭包特性来模拟块级作用域
明白了块级作用域,接下来看看js怎么实现的吧:
function A(num) {
//下面是一个匿名立即执行函数
//核心代码
(funnction(){
for(var i = 0; i<num; i++) {
num++;
}
})()
//核心代码结束
console.log(i)//underfined
}
使用这个就可以有效的避免全局污染,也许有人会对匿名立即执行函数为什么是一个闭包感到困惑,如果有这个问题可以点击这里查看
二.存储变量
闭包的另一个作用是可以保存外部函数的变量
function StorageVariable(){
var x = 100;
return {
function(){
return x
}
}
}
var test = StorageVariable();//运行StorageVariable函数,生成活动变量 x被test引用
这种写法可能会用在把一些不经常变动,但是计算比较复杂的值保存起来,就可以节省每次访问的时间.
三.封装私有变量
javascript中没有私有成员的概念,我们可以把函数当做一个范围,函数内的变量就是私有变量:
function Person(){
var name = 'default';
this.getName = function(){
return name;
}
this.setName = function(value){
name = value;
}
}
var person = new Person()
console.log(person.getName())//default
console.log(person.setName('mike'))
console.log(person.getName())//mike
这样就可以像私有变量一样访问和改变person的name了。
总结
不得不说写博客总结对学习这种比较难的东西真的很有用,明明我昨天感觉自己已经大概弄明白了,但在写着写着的时候又陷入了困惑,虽然写完这个不敢说已经完全弄懂了,但至少比昨天强了,但要完全掌握还任重而道远,还得靠多使用。同时也得感谢
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。