hello,闭包

2018-06-13 admin

定义

当函数可以记住并访问它定义时候的作用域,就产生了闭包。也就是说,一个函数在另外一个函数里面定义,但是它执行的时候,可能是在其他的作用域,但是它还是能够凭着出生时的回忆,找到定义时的作用域,去访问里面的变量。

    function foo() {
        var a = 2;
        function bar() {
            console.log(a)
        }
        return bar;
    }

    var bar = foo();
    bar();//记住了定义时的作用域,所以还是可以访问到a,这里会输出2

为什么能够访问到定义时候的作用域呢?答案只有一个,定义闭包的函数是个重情义的家伙,考虑到那个宝宝可能随时要用到它里面的变量,都不肯被回收。没错,这样会导致foo的作用域一直没有被回收,有一点浪费内存空间。

关于this对象

一般函数的this指向的是调用它的对象。由于闭包函数是由window调用的,所以一般它的this指向window。如果你需要让它指向某个对象,可以用call或者把外部的this保存起来,在里面直接使用。

    var name = 'window';
    var object = {
        name: 'My Object',
        //var that = this;
        getNameFunc: function() {
            return function() {
                console.log(this.name);
                //console.log(that.name);
            }
        }
    }

    object.getNameFunc()();//输出'window'
    object.getNameFunc().call(object);//输出'My Object'

循环和闭包

很常见的一段代码,运行结果就是输出5个5。因为这里的i没有块级作用域,也就是说闭包里面的函数访问到外部的变量i只有一个,加上setTimeout是异步的,执行到里面的回调的时候,外面的这个i的值就是循环结束后的值5。

    for(var i = 0; i < 5; i++) {
        setTimeout(function() {
            console.log(i);
        }, 1000)
    }

在没有let的时候,我们都是通过模仿块级作用域来解决。这个时候,闭包函数定义的作用域变成了(function(){}),然后在这个作用域里面把i的值赋值给j,每个闭包函数访问到的j就是它定义时候作用域已经保存好了的,自然就能够正确的输出。

     for(var i = 0; i < 5; i++) {
         (function() {
            var j = i;
            setTimeout(function() {//闭包
                console.log(j);
            }, 1000)
         })()
    }

当然,我们一般都舍不得再用一个j来保存,直接用传参数的形式,让块级作用域可以访问到i的值。

     for(var i = 0; i < 5; i++) {
         (function(j) {
            setTimeout(function() {//闭包
                console.log(j);
            }, 1000)
         })(i)
    }

简单改一下,每次用个块级作用域的let来保存一下是不是就可以了啊

    for(var i = 0; i < 5; i++) {
        let j = i;
        setTimeout(function() {
            console.log(j);
        }, 1000)
    }

哈哈哈,真的就输出0 1 2 3 4 5了。因为闭包记住了它定义时候的作用域呀,这个时候的j是块级的,能够好好地保存起来被闭包函数使用。 其实就是相当于每次循环都会去声明一个j,然后这个j的作用域就属于这次循环,所以可以直接把j的赋值写在for循环里。

    for(let j = 0; i < 5; i++) {
        setTimeout(function() {
            console.log(j);
        }, 1000)
    }

模块化

可以使用闭包来实现模块化的。

    var module = (function(window) {
        function test1() {
        }
        functon test2() {
        }

        return {
            test1: test1,
            test2: test2
        }
    })(window)

原文链接:https://segmentfault.com/a/1190000015269547

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-33918.html

文章标题:hello,闭包

相关文章
JavaScript包装对象使用详解
JavaScript对象是一种复合值:它是属性和已命名值的集合。通过&quot;.&quot;符号来引用属性值。当属性值是一个函数时,称为方法。 ①一段你常用但却未必明白其真正底层原理的代码: var s = &quot;hello wor...
2017-03-27
javascript基本包装类型介绍
为了便于操作基本类型值,ECMAScript 提供了 3 个特殊的引用类型:Boolean、Number和 String。这些类型与其他引用类型相似,但同时也具有与各自的基本类型相应的特殊行为。实际上,每当读取一个基本类型值的时候,后台就会...
2017-03-22
JS实现动态移动层及拖动浮层关闭的方法
本文实例讲述了JS实现动态移动层及拖动浮层关闭的方法。分享给大家供大家参考。具体实现方法如下: &lt;html&gt; &lt;head&gt; &lt;title&gt;动态移动的层&lt;&#x2F;title&gt; &lt;bod...
2017-03-23
webpack4 css打包压缩问题
这两天一直在练习这个webpack4, 发现有好多问题和坑,做开发嘛,一定要有喜欢出问题并喜欢解决问题,坚决踩个坑填个坑的不怕死小强精神! webpack4 在配置上其实是可以是想production和development的, &#x2F...
2018-05-18
浅谈js 闭包引起的内存泄露问题
在js闭包中,可以定义“局部变量”,但是外部去调用的话,尤其是反复调用赋值,会造成内存的大量开销。如何防止这种现象的发生?关于闭包还有没有类似的内存或效率问题需要注意?如何去规避? 内存问题可能是如下原因造成: 1. 循环引用导致了内存泄漏...
2017-03-24
JS判断字符串包含的方法
本文实例讲述了JS判断字符串包含的方法。分享给大家供大家参考。具体如下: 1.  例子: var tempStr = &quot;tempText&quot; ; var bool = tempStr.indexOf(&quot;Texxt...
2017-03-23
JavaScript 匿名函数和闭包介绍
匿名函数:没有名字的函数; 闭包:可访问一个函数作用域里的变量的函数; 一 匿名函数 &#x2F;&#x2F; 普通函数 function box(){ &#x2F;&#x2F; 函数名是box; retu...
2017-03-22
JS实现定时自动关闭DIV层提示框的方法
本文实例讲述了JS实现定时自动关闭DIV层提示框的方法。分享给大家供大家参考。具体分析如下: 这里用JS设定时间去控制指定ID的DIV层是否显示,可以实现一个自动关闭的提示框,时间一到,马上关闭,这样会使你的网页更人性一点,代码其实比你想像...
2017-03-23
遮罩层点击按钮弹出并且具有拖动和关闭效果(两种方法)
首先给大家展示演示效果: 基于JavaScript的网页弹出层,鼠标按在弹出层的标题栏处,可以拖动该浮动层随意移动位置,不需要时也可以关闭,操作体验舒服,兼容性好,IE/火狐等众多浏览器下运行稳定、反应快速。代码表现方面,简洁务实,不玩虚...
2017-03-29
JavaScript实现自动弹出窗口并自动关闭窗口的方法
本文实例讲述了JavaScript实现自动弹出窗口并自动关闭窗口的方法。分享给大家供大家参考。具体如下: 这里介绍的JavaScript自动弹出窗口并自动关闭窗口,JS实现此特效似乎很简单,打开网页后即显示一个弹出窗口,之后会自动离开,使用...
2017-03-27
回到顶部