资讯专栏INFORMATION COLUMN

闭包

vslam / 2393人阅读

摘要:本质与解析当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。

本质与解析

当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。

function outter() {
  var a = 1
  function inner() {
    console.log(a)
  }
  return inner
}
var accept = outter()
accept() // 1

在此例中,将内部函数inner作为返回值,当outter函数执行后,赋值给accept,并且调用accept;实际上调用了inner函数,它在自己定义的词法作用域以外的地方执行。
通常在outter函数执行完成之后,由于js的垃圾回收机制,其内部的作用域会被销毁回收,但是由于闭包的存在,accept持有对inner的引用,而inner声明的位置为outter的内部作用域,因此该作用能够一直存活

循环与闭包

面试常见的闭包考题就是循环闭包。例如:

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

正常情况下期待每隔一秒输出1~8,但是实际每秒输出一个9,其实不难理解,从执行栈来看,延迟函数会在整个for循环执行完成之后才会执行,即使setTimeout设置的延迟时间是0,同时其被封闭在全局的作用域中的,因此每次得到的都是对全局i变量的引用,实际上只有一个i。
可以通过立即执行函数将作用域封闭起来,同时通过自己定义一个变量j在每次迭代中存储i的值来解决这个问题,代码如下:

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

还有更加简单的解决方案,可以通过let声明来劫持块作用域,并且在这个块作用域中声明一个变量,代码如下:

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

for循环头部的let声明会有一个特殊行为,这个行为指出变量在循环的过程中不止被声明一次,每次迭代都会声明,随后每次迭代都会使用上一个迭代结束时的值来初始化这个变量,这就意味着每次循环都会声明一个新的i,且会将上一个迭代结束时的值赋给i

模块模式与闭包

模块模式实例:

function module() { //封闭函数
  var arr = [1,2,3]
  function one() {
    console.log(arr.join(""))
  }
  function another() {
    arr.push(4)
    console.log(arr.join(""))
  }
  return {
    one: one, //内部函数
    another: another
  }
}
var accept = module()
accept.one() //123 创建一个新的模块实例
accept.another() //1234 创建一个新的模块实例

解析:module是一个函数,需要通过调用它来创建一个模块实例。其返回一个{key:value}形式的对象,这个对象中包含内部函数的引用,将其暴露提供调用,且module内部数据变量是私有隐藏状态,这个对象返回值本质上是这个模块的公共API
分析得出模块模式需要两个必备条件:

必须有外部的封闭函数,该函数必须至少被调用一次(每次调用都会创建一个新的模块实例)

封闭函数必须返回至少一个内部函数,这样内部函数才能在私有作用域中形成闭包,并且可以访问或者修改私有的状态

模块机制
var MyModules = (function Manager() {
  var modules = {};
  function define(name, deps, impl) {
    for (var i=0; i

"one"和"another"两个模块都是通过公共API函数来定义,并且"another"接受"one"的实例作为参数注入,这就是模块之间可以存在依赖关系

以上内容是个人的一点总结,如果有错误或不严谨的地方,欢迎批评指正,如果喜欢,欢迎点赞收藏

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/88624.html

相关文章

  • JS 中的闭包是什么?

    摘要:大名鼎鼎的闭包面试必问。闭包的作用是什么。看到闭包在哪了吗闭包到底是什么五年前,我也被这个问题困扰,于是去搜了并总结下来。关于闭包的谣言闭包会造成内存泄露错。闭包里面的变量明明就是我们需要的变量,凭什么说是内存泄露这个谣言是如何来的因为。 本文为饥人谷讲师方方原创文章,首发于 前端学习指南。 大名鼎鼎的闭包!面试必问。请用自己的话简述 什么是「闭包」。 「闭包」的作用是什么。 首先...

    Enlightenment 评论0 收藏0
  • 闭包,又见闭包。。。。?

    摘要:完美的闭包,对,闭包就这么简单。这仅仅是闭包的一部分,闭包利用函数作用域达到了访问外层变量的目的。此时一个完整的闭包实现了,的垃圾回收机制由于闭包的存在无法销毁变量。 1.闭包是指有权访问另一个函数作用域中的变量的函数。 上面这段话来自 javascript 高级程序设计 第三版 P178 。作者说闭包是一个函数,它有访问另一个函数作用域中的变量的能力。 2.函数访问它被创建时所处的...

    keelii 评论0 收藏0
  • @noescape @escaping @autoclosure

    摘要:默认,弃用,函数结束后,这个闭包的生命周期也将结束。自动闭包默认非逃逸闭包也可以被自动的生成,这种闭包被称为自动闭包,自动闭包自动将表达式封装成闭包。 @noescape 非逃逸闭包 当闭包作为参数传递进函数时,如果这个闭包只在函数中被使用,则开发者可以将这个闭包声明成非逃逸的,即告诉系统当此函数结束后,这个闭包的生命周期也将结束,这样做的好处是可以提高代码性能,将闭包声明成非逃逸的类...

    LucasTwilight 评论0 收藏0
  • 多层级理解闭包

    摘要:第二梯队理解有了第一梯队的认识,我们慢慢修正大脑中对闭包的认识。理解这句话就可以很好的与闭包这两个字关联起来理解闭包这个概念了。总结第二梯队理解闭包是一个有特定功能的函数。第四梯队理解闭包通过访问外部变量,一个闭包可以维持这些变量。 闭包 闭包的概念困惑了我很久,记得当时我面试的时候最后一面有一个问题就是问题关于闭包的问题,然而到现在已经完全不记得当时的题目是啥了,但仍然能够回忆起当时...

    nemo 评论0 收藏0
  • 面试官问我:什么是JavaScript闭包,我该如何回答

    摘要:到底什么是闭包这个问题在面试是时候经常都会被问,很多小白一听就懵逼了,不知道如何回答好。上面这么说闭包是一种特殊的对象。闭包的注意事项通常,函数的作用域及其所有变量都会在函数执行结束后被销毁。从而使用闭包模块化代码,减少全局变量的污染。 闭包,有人说它是一种设计理念,有人说所有的函数都是闭包。到底什么是闭包?这个问题在面试是时候经常都会被问,很多小白一听就懵逼了,不知道如何回答好。这个...

    BenCHou 评论0 收藏0
  • Swift闭包1-基本概念

    摘要:关键字前面的是闭包的申明部分,类似函数的申明,包括参数的申明和返回值的申明后面的部分是闭包的实现。所以,参数类型和返回值类型都可以根据上下文推断出来,那么在闭包里面就可以直接省略。同理,返回值也可以直接省略。 原文链接:http://1199game.com/2016/09/S... 引言   这篇文章开始主要讲解Swift中闭包(Closures)的一些知识点。本文是这个系列的第一篇...

    Nekron 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<