1

昨天在看思否时,发现了一篇文章是关于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);

答案是:并不是,重新看一下闭包的定义,就明白了:
clipboard.png

它能吗?明显不能,当你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了。

总结

不得不说写博客总结对学习这种比较难的东西真的很有用,明明我昨天感觉自己已经大概弄明白了,但在写着写着的时候又陷入了困惑,虽然写完这个不敢说已经完全弄懂了,但至少比昨天强了,但要完全掌握还任重而道远,还得靠多使用。同时也得感谢

参考文章

js闭包的应用
让你分分钟理解 JavaScript 闭包
闭包,懂不懂由你,反正我是懂了

笙歌会停
1k 声望45 粉丝

代码成就万世基积沙镇海 梦想永在凌云意意气风发