js闭包的应用

前言

以前发了一篇文章,写了一些对于闭包的理解。如今补上闭包的应用篇。本文主要分享一些常见的闭包用法和分析,也但愿能增长对闭包的理解。javascript

简单回顾

在以前的文章里,讲解了闭包的原理,若是忘记了能够点击这里再看一下,在这里咱们简单回顾一些知识点:java

  • 闭包的本质是一个函数
  • 闭包能够访问函数内部变量
  • 闭包的存在会使内部变量保留在内存中

闭包的应用

闭包常见的用法,就将围绕这些特色展开:segmentfault

1.模仿块级做用域

首先简单举个例子来,解释一下什么是块级做用域:闭包

function A(){
    for(var i = 0; i < 3; i++){
        console.log(i)
    }
    
    console.log(i) // 在循环体外依然能够读到i 输出3
}
A();

在这个简单的函数中,变量i是在for循环中定义的,若是是在C++或者Java中,这样定义的变量,一旦循环结束,变量也就随之销毁,i的做用范围只在循环这个小块,就称为块级做用域。在javascript中,没有这样的块级做用域,前面一篇文章已经提到,变量是定义在函数的活动对象中的,所以,从定义i开始,在函数内部能够随时访问它。
这样的坏处显而易见:因为javascript不会告诉你变量是否已经被声明,容易形成命名冲突,若是是在全局环境定义的变量,就会污染全局环境,所以能够利用闭包特性来模拟块级做用域。不过在此以前要先介绍另外一个知识点:匿名当即执行函数。若是已经比较熟悉的同窗能够直接跳过这一块:函数

匿名当即执行函数

首先举个例子(我比较喜欢举例,感受看例子比较更容易理解):this

var helloWorld = function(){
    alert('Hello world')
}
helloWorld();//执行函数

上面的简短代码一共就作两件事:1.定义了一个匿名函数并赋值给helloWorld;2.在helloWorld后面加括号表示调用函数,因此 匿名函数若是直接执行,是否是应该这样写:code

function(){
    alert('Hello world')
}()

这样的写法会报错,由于在javascript中,function是函数声明的标志,不容许在后面直接加括号,而应该写成这样:对象

(function(){
    //函数体
    alert('Hello world')
})()

也就是把声明部分加括号便可,加了括号之后,这一段代码就至关于执行了里面的函数体部分,可是此时内部的变量已经不能被外部访问,请看下面详细样例继承

具体实现

如今咱们讲模拟块级做用域的具体步骤,假设仍是针对前面的A函数,若是咱们想让i变量只有块级做用域,能够这样写:ip

function A() {
    //核心代码
    (function(){
        for(var i = 0; i<3; i++) {
            console.log(i);
        }
    })()

    // 如今,做用域外没法访问到i了
    console.log(i)//underfined
}
A();

注意看核心代码部分,咱们用刚刚讲到的匿名自执行函数在内部造成了一个闭包,这个闭包在哪呢?一直强调,闭包的本质是函数,其实在这里闭包就是那个匿名函数,这个闭包能够到函数A内部的活动变量,又能保证本身内部的变量在自执行后直接销毁,这个应该不难理解了

优势分析

这种写法的常常用在全局环境中,能够避免添加太多的全局变量和全局函数,特别是多人合做开发的时候,能够减小所以产生的命名冲突等,避免污染全局环境。

2.存储变量

咱们知道闭包的另外一个特色是能够保存外部函数的变量,原理是基于javascript中函数做用域链的特色,内部函数保留了对外部函数的活动变量的引用,因此变量不会被释放(这一块没有理解清楚的请看前一篇文章,里面讲的比较详细),而后咱们再来愉快地举例子:

function B(){
    var x = 100;
    return {
        function(){
            return x
        }
    }
}
var m = B()//运行B函数,生成活动变量 x被m引用

这是前文介绍过的一个最简单的闭包例子,咱们运行B函数,返回值就是B内部的匿名函数,此时m引用了变量x,因此B执行后x不会被释放,利用这一点,咱们能够把比较重要或者计算耗费很大的值存在x中,只须要第一次计算赋值后,就能够经过m函数引用x的值,没必要重复计算,同时也不容易被修改

优势分析

这种写法可能会用在把一些不常常变更,可是计算比较复杂的值保存起来,就能够节省每次访问的时间。

3.封装私有变量

javascript中没有私有成员的概念,咱们能够把函数当作一个范围,函数内的变量就是私有变量,在外部没法引用,好比:

function C(a,b){
    var c = a - b ;
    return c
}

在这个函数中,a b c都是私有变量,在外部没法访,利用闭包的特色,咱们能够就能够建立能够访问私有变量的方法:

function Person(){
    var name = 'default';
    this.getName:function(){
        return name;
    }
    this,setName:function(value){
        name = value;
    }
}
console.log(Person.getName())//default
console.log(Person.setName('mike'))
console.log(Person.getName())//mike

在这个例子中,设置了两个闭包函数来操做Person函数内部的name变量,除了这两个函数,在外部没法再访问到name变量,name也就至关因而私有成员。在这个例子中,咱们用的是在构造函数中定义公有方法,对于全部的Person实例,都分别建立了新的办法,固然还可使用其余形式来避免这个问题,要涉及到建立对象模式的一些知识,在这里说明怕反而增长了闭包的理解难度,以后在写对象和继承的时候再提到(下一次更新必定不会这样久了QAQ)。

小结

关于闭包的主要主要应用就讲到这里,本文中不少知识点与上一篇文章有关,又由于发布相隔时间比较长(个人锅),建议你们能够先看看上一篇复习一下,这篇相对来前一篇容易理解,并且在举例过程尽可能没有加入其它的疑难知识点,但愿能对看到的人有所帮助。以上内容属于我的看法,若是有不一样意见,欢迎指出和探讨。同时,码字不易请尊重做者的版权,转载请注明出处,如做商用,请与做者联系,感谢!

补充

若是看完对您有帮助,顺手点个推荐呗~

相关文章
相关标签/搜索