美文网首页
闭包, 定时器

闭包, 定时器

作者: 老虎爱吃母鸡 | 来源:发表于2016-10-04 18:57 被阅读0次
    • 什么是闭包? 有什么作用
      • 闭包的形成
        在高级程序设计3中对于闭包的定义是这样的
        <blockquote>有权访问另一个函数作用域中的变量的函数。</blockquote>
        在Wikipedia中的定于是这样的
        <blockquote>引用了自由变量的函数。</blockquote>
        一开始,我对这样的抽象概念很模糊,但是当我理解了闭包之后,我又认为这样的定义是简介而有力的,如果从理解闭包的定义来说,可以认为JS中的所有函数都是闭包,因为每个函数都能访问到全局作用域的自由变量
    var a = 1
    function fn() {
        console.log(a)
    }
    fn()
    

    在这个例子中,fn可以访问了全局变量a,这个函数就叫做闭包,当然,这只是从理解的角度来说,实际上这样的全局作用域下的闭包是没意义的,因为全局的变量对象不会被销毁。在函数内部的闭包可以在chrome的开发者工具看到


    2016-08-19_154334.png

    要理解闭包的和闭包的作用,就要从作用域链的形成开始,通过下面的例子来说明

    var a =2
    function fn() {
        var a = 1
        function fn2() {
            console.log(a)
        }
        fn2()
    }
    fn()
    

    因为js是词法作用域,当函数fn声明的时候,就会预先包含全局作用域链,然后放在fn.Scope中,[[Scope]]是一个只有语言内部才能访问的属性,当函数fn被调用的调用的时候,会创建一个执行环境,执行环境里面有两个东西,一个是变量对象在函数内部又叫活动对象,一个是作用域链,作用域链的形成就是复制fn.Scope里面的变量对象,然后推入当前的活动对象。当fn执行完的时候,本来fn执行环境的变量对象和作用域链都会销毁,但是现在只有作用域链销毁了,变量对象却没有销毁,因为内部的函数fn2的作用域链在引用这fn的变量对象。因为fn2的作用域链里面包含fn的变量对象,所以可以访问到fn的变量,所以也就形成了闭包。
    - 闭包的缺点
    1. 在IE9之前因为使用不同的垃圾收集机制会导致循环引用会造成内存泄漏
    2. 闭包会携带包含函数的作用域,所以会比其他函数占用更多内存,过度使用闭包会造成内存占用过多
    - 闭包的用法
    其实保存变量现场,封装私有变量都是对闭包特性的利用,并不是闭包的定义,不要混淆
    1. 保存变量现场,主要利用了js函数传递参数的方式是按值传递

    !function() {
        var arr = []
        for (var i = 0; i < 5; i++) {
            arr[i] = function () {
                alert(i)
            }
        }
        arr[1]()//5
    }()
    

    本来的打算应该数字的每一项都是一个函数,可以打印出每一项的索引,但是因为所访问的i是外部函数的,当循环完以后,i已经累加到5了,所以无论多少输出当然是5,我们可以利用js函数传递是按值传递的方式来改造这个数组

    !function() {
        var arr = []
        for (var i = 0; i < 5; i++) {
            arr[i] = function (n) {
                return function () {
                    alert(n)
                }
            }(i)
        }
        arr[1]()//5
    }()
    

    改造后的函数输出就是1,主要利用按值传递参数和闭包
    2. 封装私有变量
    有时候我们常常需要隐藏一些数据,而仅仅暴露一些接口供外部使用,起到封装的效果,这时候就可以利用闭包

    var Car = (function () {
        var speed = 0
        return {
            setSpeed: function (s) {
                speed = s
            },
            getSpeed: function () {
                return speed
            }
        }
    })()
    Car.setSpeed(30)
    Car.getSpeed()
    

    这就封装了一个汽车对象,其中是speed私有的变量,只能通过我们提供的接口setSpeed和getSpeed来访问到

    • setTimeout 0 有什么作用
      setTimeout表示的是超时调用,setTimeout可以接受多个参数,表示过延迟多长时间再执行回调函数
      • 第一个参数表示回调函数,可以是一个字符串或者是一个函数名,推荐使用函数名,因为字符串会导致一定的损耗和安全问题
      • 第二个参数表示延迟的时间,单位是ms毫秒,因为js是单线程的解释器,所以一次只能执行一段代码,为了控制要执行的代码,就有一个任务队列,这些任务就会按照他们添加到任务队列的顺序执行,延迟的时间表示再过多少ms才把当前任务添加到任务队列,如果队列前面没有任务,当前任务就会立即执行,如果队列前面有任务,就要等到前面的任务执行完之后再执行
      • 第三个和后面的参数表示参数回调函数的参数
        setTimeout(f,0)表示的就是尽快的执行函数f,他的作用可以调整时间的发生顺序,例如在开发中,某个事件发生在子元素,然后冒泡到父元素,即子元素的回调函数会比父元素的回调函数先执行,通过setTimeout(f,0)我们就可以让子元素的回调函数排在队列后面,从而让父元素的回调函数先执行
        参考:
        定时器-阮一峰

    相关文章

      网友评论

          本文标题:闭包, 定时器

          本文链接:https://www.haomeiwen.com/subject/gqristtx.html