JS-闭包

171 阅读4分钟

01 什么是闭包

//闭包为fn2函数,能够读取其他函数内部变量的函数
//闭包的作用 使函数外部变量能读取到函数内部变量
/*闭包的特点:闭包可以记住诞生的环境,
fn2记住了它的诞生环境是fn,故fn2可以得到fn的所有内部变量*/
//闭包的本质:闭包就是函数内部和函数外部连接的桥梁
var a =1;
function fn(){
    console.log(a);
    var b = 2;
    function fn2(){
        console.log(b);
    }
    return fn2;
}
var result = fn();
result();

02 闭包的用途

//1.计数器

//作用:读取函数内部的变量,这些变量始终在内存中
//使用闭包之后小心内存泄露 要释放当前变量 这个例子里是result
function a() {
    var start = 0;
    function b() {//因为b函数一直没有被释放
        return start++;//所以start一直存在 函数没有被释放的原因是
    }
    return b;
}
var result = a();/*定义的result变量包含了a函数,
a函数包含了b函数,所以result不释放,里面的a,b函数都不会被释放*/
console.log(result());
console.log(result());
console.log(result());
//想要释放a,b函数或者说释放内存
result = null;
// 2.封装对象的私有属性和方法
// 先在Person函数里定义 再在setAge赋值 然后用getAge返回
function Person(name) {
    var age;
    function setAge(n) {
        age = n;
    }
    function getAge(n) {
        return age;
    }
    return {
        name: name,
        setAge: setAge,
        getAge: getAge
    }
}
var p1 = Person('qaq')
p1.setAge(18);
console.log(p1.getAge());
p1 = null;

立即执行函数

// IIFE ()跟在函数后面 表示调用函数fn()
// 立即执行函数:定义函数之后立即调用该函数,该函数叫立即执行函数 
//简称:自执行函数

// 常用的三种写法
(function(){})();
(function(){}());
!(function(){})();//用于两个自执行函数连接 !为连接符
//通常情况下使用第三种写法

实例

var add = (function(){
    var count = 0;
    return function (){
        return count++;
    }
})();
console.log(add());
/*这样子写在全局作用域下是调用不了count属性
  因为count为add的私有属性,如果再创建一个函数
  里面同样有count 就不会混淆 而且也减少了对全局变量的污染

循环中的闭包

function add() {
  var arr = [];
  for (var i = 0; i < 10; i++) {
      arr[i] = function(){
          return i ;
      }
  }
  return arr;
  }
var arr = add();
console.log(arr[5]());//10
console.log(arr[0]());//10
/*原因是调用add函数里的匿名函数后返回的i在该匿名函数中为自由
变量,所以会根据作用域链往它的上层查找,即add函数里。
在add函数里for循环已经很快的执行完了 所以i的值返回为10*/

用闭包方法解决

function add() {
    var arr = [];
    for (var i = 0; i < 10; i++) {
        arr[i] = (function (n) {
            return function () {
                return n;
            }
        })(i);
    }
    return arr;
}
var arr = add();
console.log(arr[5]());
console.log(arr);
console.log(arr[5]);
//原理相当于把变量保存在内存中,每次执行在内存中获取

闭包的十种应用场景

//1.返回值
    function fn() {
      var name = 'qaq'
      return function () {
        return name;
      }
    }
    var fnc = fn();
    console.log(fnc());//qaq
//2.函数赋值
    var a;
    var fn = function () {
      var b = 10;
      var c = function () {
        return b;
      }
      a = c;
    }
    fn();
    console.log(a());//10
//3.函数传参
    function fn(f) {
      console.log(f());//qaq
    }
    function fn2() {
      var name = 'qaq';
      function a() {
        return name;
      }
      fn(a);
    };
    fn2();
//4.IIFE
    function fn(f) {
      console.log(f());//qaq
    }
    (function fn2() {
      var name = 'qaq';
      function a() {
        return name;
      }
      fn(a);
    })();
//5.循环赋值
function fn() {
      var arr = [];
      for (var i = 0; i < 10; i++) {
        arr[i] = (function (n) {
          return function () {
            return n;
          }
        })(i);
      }
      return arr;
    }
    var bar = fn();
    console.log(bar[1]());//1
//6.getter和setter
      var getter, setter;
      (function () {
        var num = 18;
        getter = function () {
          return num;
        }
        setter = function (n) {
          num = n;
        }
      })();
      console.log(getter());//18
      setter(28);
      console.log(getter());//28
//7.迭代器
    function add() {
      var count = 0;
      return function () {
        return count++;
      }
    }
    var fnc = add();
    console.log(fnc());//0
    console.log(fnc());//1
    console.log(fnc());//2
//8.区分首发
    function def() {
      var list = [];
      return function (id) {
        if (list.indexOf(id) > -1) {
          return false
        } else {
          list.push(id);
          return true;
        }
      }
    }
    var fnc = def();
    console.log(fnc(10));//true
    console.log(fnc(10));//false
//9.缓存机制
    给一串数字返回这些数字的和 
    var mult = (function fn() {
      var save = {};//缓存区域
      var add = function () {//用给的数求和
        var sum = 0;
        for (var i = 0; i < arguments.length; i++) {
          sum = sum + i;
        }
        return sum;
      }
      return function () {
        var arr = Array.prototype.slice.apply(arguments);//实参转化为数组
        console.log(save);
        if (arr in save) {//判断缓存里是否已经存在
          return save[arr];//有的话直接返回值
        } else {//没有的话求和返回值
          return save[arr] = add.apply(null, arguments);
        }
      }
    })();
    console.log(mult(1, 2, 3, 4, 5));//10
    console.log(mult(1, 2, 3, 4, 5));//10
    console.log(mult(1, 2, 3, 4, 5, 6, 7));//21
//10.img对象图片上报
    var report = (function (src){
      var imgs = [];
      return function (src){
        var img = new Image();
        imgs.push(img);
        img.src = src;
      }
    })();
    report('http://xxx.com/xxx/x');