美文网首页
随手记一记之【函数表达式与闭包】

随手记一记之【函数表达式与闭包】

作者: woodccc | 来源:发表于2018-07-24 14:19 被阅读0次

参考

定义函数

定义函数有两种方式:一是函数声明,而是函数表达式。

函数声明重要的特征是,函数声明提升——在执行代码之前会先读取函数声明,这就意味着可以把函数声明放在调用此函数的语句后面。

sayHi()

function sayHi() {
    console.log('hi')
}

// hi

然而,函数表达式没有这种特性,比如说:

sayHi()

const sayHi = function() {
  console.log('hi')
}

//error: Uncaught TypeError: sayHi is not a function

闭包

定义

闭包是指有权访问另一个函数作用域中的变量的函数 ——JavaScript 高级程序设计(第三版)

看了红宝书的闭包,和很多关于闭包的文章。觉得还是红宝书的描述规范一点,怎么理解这句话呢?简单来说就是函数能访问别的函数的变量,这个函数就是闭包。

把闭包简单理解成"定义在一个函数内部的函数"。—— 学习Javascript闭包(Closure)——(阮一峰)

闭包用途——读取函数内部的变量

function A() {
  var value = 999
  function B() {
    console.log('value', value)
  }
  B()
}
A() //999

函数 B 在函数 A中定义,那么函数 B 可以访问 A 中的变量(还可以访问全局变量)。函数 B 就是闭包,很简单吧。再看:

function A() {
  var value = 999
}
function B() {
  console.log('value', value)
}
B()
//报错: Uncaught ReferenceError: value is not defined

此时,函数 B 不能访问函数 A 中的 value,B就不是闭包。就是这样子

经常会看到用两个括号的方式使用闭包,例如:

(function(value) {
  function B() {
    console.log(value)
  }
  B()
})(999)

// 999

以前一直不明白这是什么意思,其实仔细看下。就是一个立即执行的匿名函数,匿名函数中的函数 B 能访问匿名函数的变量(参数),函数 B 就是闭包。

闭包用途—— 让变量的值始终保持在内存中

function f1() {
  var name = 'MyName'
  function sayHello() {
    alert('hello ' + name)
  }

  sayHello()
}
f1() // hello MyName

这段代码,当 f1执行后,变量 name就会回收。再看下面:

function f1() {

  var name = 'MyName'

  function sayHello() {
    alert('hello ' + name)
  }

  return sayHello

}

var result = f1()

result() // hello MyName

函数 f1 返回了函数 sayHello,并保存在全局变量 result 中,这里 result 就是 sayHello 函数闭包。无论调用多少次 result 都能访问 f1函数内的变量 name,这就意味着name 一直在内存中,并没有在f1执行后被回收。

经典面试题

要求每隔一秒打印 1、2、3、4、5,很容易写出这样的代码来:

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

结果是每隔一秒打印了一个6出来。由于setTimeout是异步的,首先会把循环执行完。等到打印时,变量 i 已经是6了,于是打印了5个6。

解决办法:闭包

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

这里为什么就不是打印6呢?timer就是闭包,time 访问的是 匿名函数的参数 j 。相当于循环里面调用了5次匿名函数,每次传给匿名函数的参数分别是1、2、3、4、5。可以理解为每次调用匿名函数,都给其参数 j 赋值 i。所以最终可以正确打印1、2、3、4、5。

解决这个问题还要其他的办法。
方法一:setTimeout 第三个参数

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

方法二: 用 let 声明变量

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

相关文章

  • Swift汇编分析闭包-内存布局

    1、闭包表达式与闭包 闭包表达式也就是定义一个函数。一般我们可以通过func定义一个函数,也可以通过闭包表达式定义...

  • Swift语法 -- [07 - 闭包]

    在Swift中,可以通过func定义一个函数,也可以通过闭包表达式定义一个函数 1 闭包表达式 闭包表达式 闭包表...

  • Swift 5基础语法要点整理—闭包

    闭包 闭包表达式 在Swift中,可以通过func定义一个函数,也可以通过闭包表达式定义一个函数 闭包表达式的简写...

  • Swift-闭包

    闭包表达式 在swift中,可以通过func定义一个函数,也可以通过闭包表达式定义一个函数 闭包表达式简写 尾随闭...

  • 高级语言特性

    闭包 闭包的概念、形式与应用 Lambda表达式 Lambda表达式让Spark编程更容易 OOP AOP 函数编...

  • Kotlin学习之高阶函数和Lambda表达式:闭包

    Kotlin学习之高阶函数和Lambda表达式:闭包 一、闭包 闭包指Lambda表达式和匿名函数外部定义的局部变...

  • 闭包

    闭包表达式 在swift中,可以通过func定义一个函数,也可以通过闭包表达式定义一个函数 闭包表达式的简写 尾随...

  • Swift--闭包

    闭包表达式 在Swift中,可以通过 func定义一个函数,也可以通过闭包表达式定义一个函数 闭包表达式的简写 尾...

  • swift基础——闭包表达式和闭包

    一、闭包表达式 在Swift中,可以通过func定义一个函数,也可以通过闭包表达式定义一个函数 闭包表达式格式如下...

  • Swift基础语法-闭包,闭包函数回调,尾随闭包,闭包捕获值,循

    本节知识点 闭包的基本概念 闭包基本使用 闭包表达式作为回调函数 闭包的多种写法(尾随闭包) 闭包表达式优化 闭包...

网友评论

      本文标题:随手记一记之【函数表达式与闭包】

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