Javascript

JS中的闭包

本文主要是介绍JS中的闭包,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

JS中的闭包

  • 引入
    需求: 点击某个按钮, 提示"点击的是第 n 个按钮"
var btns = document.getElementsByTagName('button')
for (var i = 0,length=btns.length; i < length; i++) {
    var btn = btns[i]
    //将btn所对应的下标保存在btn上
    btn.index = i
    btn.onclick = function () {
      alert('第'+(this.index+1)+'个')
    }
  }

  //利用闭包
  for (var i = 0,length=btns.length; i < length; i++) {
    (function (j) {
      var btn = btns[j]
      btn.onclick = function () {
        alert('第'+(j+1)+'个')
      }
    })(i)
  }
  • 如何产生闭包?
    • 当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时, 就产生了闭包
      • 函数嵌套
      • 内部函数引用了外部函数的数据(变量/函数)
  • 闭包到底是什么?
    • 理解一: 闭包是嵌套的内部函数(绝大部分人)
    • 理解二: 包含被引用变量(函数)的对象(极少数人)
    • 注意: 闭包存在于嵌套的内部函数中
    • 闭包本质是内部函数中的一个对象, 这个对象中包含引用的变量属性
  • 常见闭包
      1. 将函数作为另一个函数的返回值
    function fn1() {
      var a = 2;
      function fn2() {
        a++;
        console.log(a);
      }
      return fn2;
    }
    var f = fn1();
    f();
    f();
    
      1. 将函数作为实参传递给另一个函数调用
    function showDelay(msg, time) {
      setTimeout(function () {
        alert(msg)
      }, time)
    }
    showDelay('atguigu', 2000)
    
  • 闭包的作用:
    • 使用函数内部的变量在函数执行完后, 仍然存活在内存中(延长了局部变量的生命周期)
    • 让函数外部可以操作(读写)到函数内部的数据(变量/函数)
    • 函数执行完后, 函数内部声明的局部变量是否还存在? //一般是不存在, 存在于闭中的变量才可能存在
    • 在函数外部能直接访问函数内部的局部变量吗? //不能, 但我们可以通过闭包让外部操作它
  • 闭包的生命周期
    • 产生: 在嵌套内部函数定义执行完时就产生了(不是在调用)
    • 死亡: 在嵌套的内部函数成为垃圾对象时,f = null
  • 闭包应用:
    • 模块化: 封装一些数据以及操作数据的函数, 向外暴露一些行为
    (function (window) {
    //私有的数据
    var msg = 'atguigu'
    var names = ['I', 'Love', 'you']
    //操作数据的函数
    function a() {
        console.log(msg.toUpperCase())
    }
    function b() {
        console.log(names.join(' '))
    }
    window.coolModule2 =  {
        doSomething: a,
        doOtherthing: b
    }
    

})(window)

* 循环遍历加监听
* JS框架(jQuery)大量使用了闭包
* 缺点:
* 变量占用内存的时间可能会过长
* 可能导致内存泄露
* 解决:
  * 及时释放 : f = null; //让内部函数对象成为垃圾对象
*************
## 面试题
* 1.
```js
//代码片段一
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
  return function(){
    return this.name;
  };
}
};
alert(object.getNameFunc()());  //?  the window
//代码片段二
var name2 = "The Window";
var object2 = {
name2 : "My Object",
getNameFunc : function(){
  var that = this;
  return function(){
    return that.name2;
  };
}
};
alert(object2.getNameFunc()()); //?  my object
function fun(n,o) {
console.log(o)
return {
  fun:function(m){
    return fun(m,n)
  }
}
}
var a = fun(0)
a.fun(1)
a.fun(2)
a.fun(3)//undefined,0,0,0
var b = fun(0).fun(1).fun(2).fun(3)//undefined,0,1,2
var c = fun(0).fun(1)
c.fun(2)
c.fun(3)//undefined,0,1,1

内存溢出与内存泄露

  1. 内存溢出
  • 一种程序运行出现的错误
  • 当程序运行需要的内存超过了剩余的内存时, 就出抛出内存溢出的错误
  1. 内存泄露
  • 占用的内存没有及时释放
  • 内存泄露积累多了就容易导致内存溢出
  • 常见的内存泄露:
    • 意外的全局变量
    • 没有及时清理的计时器或回调函数
    • 闭包
// 1. 内存溢出
  var obj = {}
  for (var i = 0; i < 10000; i++) {
    obj[i] = new Array(10000000)
    console.log('-----')
  }
  // 2. 内存泄露
    // 意外的全局变量
  function fn() {
    a = new Array(10000000)
    console.log(a)
  }
  fn()
   // 没有及时清理的计时器或回调函数
  var intervalId = setInterval(function () { //启动循环定时器后不清理
    console.log('----')
  }, 1000)
  // clearInterval(intervalId)
    // 闭包
  function fn1() {
    var a = 4
    function fn2() {
      console.log(++a)
    }
    return fn2
  }
  var f = fn1()
  f()
  // f = null
这篇关于JS中的闭包的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!