js闭包 从片面到全面的真正理解 永不再忘!

·  阅读 157
js闭包 从片面到全面的真正理解 永不再忘!
  • js闭包 从片面到全面的真正理解 永不再忘!

第一部分(片面理解)

当初面试官问我什么是闭包,闭包的实际用途和作用时 我刚开始的回答:

  • 第一部分(片面理解)

从最初的片面理解

回答什么是闭包:函数外面能访问函数内部的局部变量;

因为自己是后端出身后来转的前端 基于对后端语言的理解 我曾经一度简单的认为闭包的作用就是简单的类似后端的共有方法和私有方法

回答闭包的实际用途: 可以写module模式 模仿后端语言的私有private和共有方法public 如:

var person = (function Moudels() {
  let name= "test";
  function getTest() {
    console.log(name);
  }
  return function getName() {
    console.log(name);
  }
  return function getAge() {
    console.log(name+'30');
  }
})();
person.getName();
person.getAge();


复制代码

公布了 两个外部方法 getName和getAge 供外部访问 内部变量name和getTest则是私有方法

第二部分(全面理解)

再当面试官再问我什么是闭包和闭包在作用和用途时 我现在的回答: /**

  • 第二部分(全面理解) 深入的理解:知道为什么会有闭包 什么样的才是闭包 什么样的场景会用到闭包

要什么样的是闭包 就要知道为什么会有闭包 如同 什么是宫保鸡丁 你就得知道为什么叫宫保鸡丁

开始深入探究 前面的片面理解的部分:

举例:


function f1() {
   var  a = 10;
   function f2() {
     alert(a);
   }
   f2()
}
f1();//可以访问到局部变量name

复制代码

以上代码算不算闭包?为什么?

分析 按照上面理解 外部 getname 可以访问到内部变量name 是不是应该算闭包 那我举下面例子反问:

function f1() {
  var name = 'test';
  return name;
}
f1();//也可以访问到局部变量name;那这样外部函数也是可以访问到内部name 变量的  是不是也算闭包
复制代码

很显然 上面两个都不算闭包

【那么开始真正理解闭包 闭包的出现不是无缘不顾 一定有他的道理 】

重点:

闭包:第一个作用是前面提到的可以读取函数内部的变量 ;

另一个作用就是让这些变量始终保存在内存中;不会再函数调用后自动销毁和释放

总结1:局部变量无法共享和长久保存;而全局变量可能会造成变量污染,当我们希望有一种机制可以长期就保存变量又不会造成全局变量污染

总结2:闭包的出现:函数返回一个内部函数;并且对局部变量有引用 则会产生闭包

//闭包写法:
function f1() {
  var a = 10;
  function f2() {
    a++;
    console.log(a)
  }
  return f2;
};
var f = f1();
f();
//当f不在调用时,a的状态会被保存,不会在f1()执行完释放
//简化写法
function f1(){
  var a =10;
  return function() {
    a++;
    console.log(a);
  }
}
var f= f1();
f();
复制代码

为加深印象 来看看控制天输出:

图一

闭包1.jpg

图二

闭包2.jpg 从图二可以知道 每一个函数都保存着对应的函数的局部变量的状态

用途总结: 接第一部分的用途 moudel模式 公有和私有方法的补充

之前在学习moudel模式时候 就有过困惑 如果单纯的只是公布公有方法和变量 那实现的方式有很多

比如 返回一个对象 对象里面包含你要公布出去方法或变量 如下:

function Person() {
   var name='test';
   function getName() {
     console.log(name);
   }
   function getAge() {
     console.log(name + '30');
   }
   function getHeight() {
     console.log('身高两米');
   }
   return {
     name:getName(),
     aget:getAge()
   }
}
复制代码

又或者 我直接定义对象 公布出去

var Person = {
  name:'',
  age:'',
  getName:function() { console.log(this.name)},
  getAge:function() {console.log(this.age)};
}
export default Person;
复制代码

总结:【 能实现一些保存状态的真正用途】

举例1:【立即执行函数在闭包中的应用】

立即执行函数在闭包中的应用

1、立即执行函数能配合闭包保存状态。

来看下 上节内容中闭包的例子:

function makeClosures(i){    
    var i = i;  
    return function(){
        console.log(i);     
    }
}

for (var i=1; i<=5; i++) {
    setTimeout(makeClosures(i),i*1000);  
}
//1
//2
//3
//4
//5
//现在,我们来利用立即执行函数来简化它:
for (var i=1; i<=5; i++) {
    setTimeout((function(i){
        return function(){
            console.log(i);
        }
    })(i),i*1000);
}
复制代码

举例2:moudle模式结合闭包 模块化中应用

现在我们结合一个简单的案例来走一遍模块化开发的流程。这个例子想要实现的功能是每个一秒,body的背景色就随着一个数字的递增在固定的三种颜色之间切换。

(1)首先创建一个专门用来管理全局状态的模块。这个模块中有一个私有变量保存了所有的状态值,并对外提供了访问与设置这个私有变量的方法,代码如下:

var module_status = (function() {
  var status = {
      number: 0,
      color: null
  }

  var get = function(prop) {
      return status[prop];
  }
  
  var set = function(prop,value) {
      status[prop] = value;
  }

  return {
      get,
      set
  }
})();
复制代码

(2)在来创建一个模块,这个模块专门负责body背景颜色的改变。

var module_color = (function() {  
  //假装用这种方式执行第二步引入模块
  //类似 import state from 'module_status';

  var state = module_status;
  var colors = ['yellow','#ccc','red'];

  function render() {
      var color = colors[state.get('number') % 3];
      document.body.style.backgroundColor = color;
  }

  return {
      render
  }
})();
复制代码

微信图片_20210625145221.jpg

分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改