js闭包

闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。

我们先来看一个闭包的例子

function father() {
    var name = "Burc";  // name 是一个被 father() 创建的局部变量
    function child() {  // child() 是内部函数,一个闭包
        alert(name);  // 使用了父函数中声明的变量
    }
    return child;
}

var myFunc = father();
myFunc();

在这个例子中,在内部函数 child() 在执行前,就已经被外部函数 father() 返回。

也许第一感觉这段代码不能运行。因为在一些编程语言中,函数中的局部变量仅在函数的执行期间可用。一旦 father() 执行完毕,我们会认为 name 变量将不能被访问。然而,因为代码运行得没问题,所以很显然在 JavaScript 中并不是这样的。

这个谜题的答案是,JavaScript中的函数会形成闭包。 闭包是由函数以及创建该函数的词法环境组合而成。这个环境包含了这个闭包创建时所能访问的所有局部变量。在我们的例子中,myFunc 是执行 father 时创建的 child 函数实例的引用,而 child 实例仍可访问其词法作用域中的变量,即可以访问到 name 变量 。

闭包的最大特性就是,如果里函数引用(or访问,这俩词在这个语境下是等价的)了外函数的某个变量,那这个变量就能享受和全局变量一样的特权,不会被回收!除非你关闭页面or浏览器!

关于内存销毁强烈推荐这篇文章 原文链接 ,简单来说就是,没有用的局部变量就会被销毁内存,而在闭包中,内部函数引用了外部函数的变量,所以外部函数的局部变量即 name 变量就可以具有全局变量的某种特权,不会被回收,不会被销毁。
如果不是很理解,我们看一下下面这两个例子

 //例一
btn.onclick = function (){
        var num = 1;
        num++;
        console.log(num);
 }   
//例二
(function (){
       var num = 1;
       btn.onclick = function (){
            num++;
            console.log(num);
       }  
})();

对于例一来说,每次控制台输出都是1,因为在函数执行完毕变量num就被销毁,但是对于例二来说,控制台依次输出1,2,3...... 因为内部函数引用了外部函数的变量,所以外部函数的局部变量没有被销毁。

在循环中创建闭包,一个经典的问题

<body>
    <!-- 在页面添加三个按钮 -->
    <input type="button" value="1">
    <input type="button" value="2">
    <input type="button" value="3">

    <script>
        // 获取页面所有的input
        var aBtn = document.getElementsByTagName("input");

        // 循环绑定点击事件,当然毫无疑问这里点击之后会弹出3,
        //因为我们知道js是单线程的,当基本逻辑语句执行完之后,才会执行点击事件
        //而当你触发点击事件的时候,for循环都已经跑完了,所以i已经变成了3;
        // for(var i = 0; i < aBtn.length; i++){
        //     aBtn[i].onclick = function(){ 
        //         console.log(i);
        //     }
        // }

        // 解决方法1:也是最简单的方法,就是将for循环的var变成let
        //这样当点击每个按钮的时候,就会依次弹出0,1,2;
        //let是ES6新增的一个变量声明方式,拥有块级作用域;
        for(let i = 0; i < aBtn.length; i++){
            aBtn[i].onclick = function(){
                console.log(i);
            }
        }

        //解决方法2:利用闭包(说是闭包,貌似也不完全是),也就是函数作用域访问原则的特性
        //函数内部可以访问外部的变量,外部却访问不了里边的;
        //个人感觉主要是在匿名函数里面的i变量没有被销毁内存
        // for(var i = 0; i < aBtn.length; i++){
        //     (function(i){
        //         aBtn[i].onclick = function(){
        //             console.log(i);
        //         }
        //     })(i);
        // }
    </script>
</body>

参考链接

让你分分钟理解 JavaScript 闭包

JS-原生/一个例子讲清楚什么是闭包,什么是内存销毁

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 前言 总括 :这篇文章使用有效的javascript代码向程序员们解释了闭包,大牛和功能型程序员请自行忽略。 译者...
    KX九五阅读 282评论 0 1
  • 前言 总括 :这篇文章使用有效的javascript代码向程序员们解释了闭包,大牛和功能型程序员请自行忽略。 译者...
    秦至阅读 755评论 0 19
  • 前言 这篇文章使用有效的javascript代码向程序员们解释了闭包,大牛和功能型程序员请自行忽略。 基础篇 闭包...
    kiaizi阅读 373评论 0 7
  • 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。 一、变量...
    风萧萧易水寒_1196阅读 265评论 0 0
  • 你的胸肌是否进入了瓶颈期?来试试这套胸部训练计划。这是一套快速燃烧肌肉的训练方法,不会让你在健身房浪费大量...
    小伟健身阅读 454评论 0 1