梦想吧

302 分类: WEB前端

JS闭包问题

闭包是js经常遇到的一种场景,其含义是指 能够访问其他函数作用域中变量的函数 闭包就是一个函数,该函数可以访问其他函数作用域中的变量
比如:

function test () {
  var a = 1
  function fn () {
    console.log(a)
  }
  fn()
}
var testFn = test()
testFn()

其中,fn就是一个闭包函数,因为他可以访问test函数下的a变量

正常来说,当test函数执行完毕之后,他的作用域会被销毁,垃圾回收机制会释放其内存空间,但是实际上并没有,应为fn还存在对于test作用域下的引用,而这个引用就是闭包

再如:
很久以前我们在写jquery插件的时候

// 这是一个立即执行函数,同样它也是一个闭包
(function ($) {
  // ...
})(jQuery)

该方法被执行的时候传入 jQuery 对象, 而 $ 则是作为方法的参数接受 jQuery 的值, 代表的就是 jQuery 对象,为了避免全局污染

再比如:

function warp (msg, t) {
  setTimeout(function () {
    console.log(msg)
  }, t)
}
warp('hello, 闭包', 3000)

setTimeout内部的匿名函数,这个函数有来自warp函数作用域的变量,而这个匿名函数实际上就是一个闭包,因此当300毫秒执行之后,函数可以输出信息

再来谈谈一个面试常见的问题

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

这段代码的打印结果是5个5,原因就是i定义在全局对象中,在for循环执行完成之后i的值实际结果为5了,执行setTimeout代码中的i时,全局作用域的i已经是5了,结果就是5个5
那么实际上这里可已使用闭包,在循环的时候产生一个私有作用域,在私有作用域中访问当前i的值

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

此处的setTimeout方法外层包含一个立即执行函数,通过i作为参数传递,selfI接受i的值,匿名函数中的私有变量selfI,被setTimeout中的函数调用,实现了一个闭包,这时候的selfI就是当前i的值,而打印的结果也就是 0, 1, 2, 3, 4

闭包的优缺点

优点

  • 私有作用域,防止变量命名冲突

缺点

  • 比普通函数更占用内存,解决方法就是将引用的函数对象变量设置为null

转载自https://www.daiwei.org/blog/detail?id=30

#JS, JavaScript

作者: Jim

版权: 除特别声明,均采用BY-NC-SA 4.0许可协议,转载请表明出处

目录Content

评论