首页 > 编程语言 >个人对 JavaScript 闭包的理解

个人对 JavaScript 闭包的理解

时间:2022-08-30 01:11:46浏览次数:42  
标签:闭包 函数 作用域 JavaScript add 理解 del let

作用域的概念

同级作用域

在一个作用域中声明相同名称的变量会发生变量名冲突的问题。假如在作用域 A 中声明一个变量 a,作用域 B 也声明一个变量 a,两个作用域的变量都互不影响。

// 作用域 A
{
  let a = 0;
  console.log(a);
}

// 作用域 B
{
  let a = 10;
  console.log(a);
}

第一个打印 0,第二个打印 10。

嵌套作用域

作用域是可以嵌套的,作用域 A 嵌套作用域 B,此时两个作用域分别声明变量 a,也是不冲突的。

{// 作用域 A
  let a = 0;
  console.log(a);
  { // 作用域 B
    let a = 10;
    console.log(a);
  }
}

第一个打印 0,第二个打印 10。

在嵌套作用域中,子作用域 B 可以访问父作用域 A 的变量,也可以影响它的父作用域 A。

{
  let a = 0;
  {
    a = 10;
    console.log(a);
  }
}

最终打印的结果是 10。

函数的闭包

JS 的类实际上就是在使用函数的闭包。每执行一次函数就是在生成一个新的作用域,这些新的作用域就像是上面提到的,它们互不影响,只有它们的子作用域可以影响父作用域,即闭包。

闭包缓存数据

function Counter(x) {
  return {
    add: y => {
      return (x = x + y);
    },
    del: y => {
      return (x = x - y);
    }
  };
}

add 和 del 都是父函数 Counter 的子函数,它们之间是一个闭包关系。创建两个 Counter 的实例:

let c1 = Counter(10);
console.log(c1.add(20));
console.log(c1.del(40));

当执行c1.add()时,左边有一个 Closure,说明已经形成了一个闭包:

Closure 中只有 x 是受闭包影响被缓存下来的数据,也就是父函数 Counter 的变量。Local 代表 add 函数自身的变量,没有与其他函数之间(或作用域)形成关系,也就不符合闭包的存在条件,只能由 add 函数自己来使用。

再继续往下执行,可以看到此时 Closure 中的 x 已经是 30:

再往下执行,调用 del 函数,再执行函数的相减操作之间,我们可以看到 Closure 中的 x 还是上一次的结果:30。

再接着往下执行一次,del 函数相减之后,Closure 中的 x 的结果是 -10:

本节小结

受闭包的影响,父函数的数据被缓存下来,子函数可以自由地使用,而且再内存中也不会被销毁。

闭包的好处

仔细观察上面的例子,add 和 del 函数都依赖了相同的变量 x,而这个 x 是父函数给的,再闭包中被缓存起来。add 和 del 只需要传递新的参数就可以参与运算,也就是说,闭包可以减少我们函数的参数传递,使得我们一个计算操作更加连贯,且降低代码耦合度。

假如不使用闭包,通过函数的参数传递来计算,替代上面的闭包函数:

function add(x, y) {
  return (x = x + y);
}

function del(x, y) {
  return (x = x - y);
}

let res = add(10, 20);
let ser = del(res, 40);

就很没有必要,何不如把 x 抽离出来呢?变成一个全局变量:

let x = 10;

function add(y) {
  return (x = x + y);
}

function del(y) {
  return (x = x - y);
}

let res = add(20);
let ser = del(40);

可以,但是不推荐,全局作用域中,变量 x 被声明一次,假如代码越写越多,变量是不是会冲突,代码是不是变得难以维护?闭包可以把 add 和 del 以及 x 都囊括在一个作用域里,也不影响其他的作用域。

本节小节

闭包可以把一块代码容纳在一个里面,形成一个整体,一个不受其他作用域影响的作用域。是不是很像模块开发?没错,我猜测 CommonJS 就是使用的闭包。

总结

  1. 闭包可以让我们使用模块开发思想来写代码,把一系列代码揉进闭包里,是一个有机的结合。类就是使用的闭包,在早期通过闭包来实现模块的开发。

  2. 闭包可以缓存父函数的变量,子函数可以使用,子函数修改父函数的变量,其他子函数也跟着改变。

标签:闭包,函数,作用域,JavaScript,add,理解,del,let
From: https://www.cnblogs.com/Enziandom/p/16637916.html

相关文章

  • 【Vue面试题】谈谈你对Vue的diff算法的理解
    1diff算法到底是什么?diff算法是一种通过同层的树节点进行比较的高效算法,它可以不用频繁操作DOM,而是选用虚拟DOM节点操作,说人话就是专门用来处理虚拟DOM节点的。2操作......
  • C++ 左值于右值的理解
    定义与区别左值(lvalue,locatorvalue)表示了一个占据内存中某个可识别的位置(也就是一个地址)的对象。即左值指的是可以取地址的变量。区分表达式的左右值属性有一个简......
  • tp+javascript 输入框/绑定邮箱
    添加数据库and绑定邮箱!!! 实现效果:  数据库设计:CREATETABLE`o_my_resume`(`id`int(11)NOTNULLAUTO_INCREMENT,`name`varchar(255)NOTNULLCOMM......
  • java 字节码指令理解
    publicclassTest{privateintnum1=1;publicstaticintNUM1=100;publicintfunc(inta,intb){returnadd(a,b);}publicint......
  • 关于java中system.out.println()中out的理解
    在Java编程中,我们常常用System.out.println()方法来输出,在集合中我经常看到使用方法引用的方式来遍历集合元素:xxx.foreach(System.out::println);也许我们都已经猜到printl......
  • javascript中的constructor
    1.使用constructor   constructor是Object类型的原型属性,它能够返回当前对象的构造器(类型函数)。利用该属性,可以检测是否复合类型数据的类型,如对象,数组和函数等。v......
  • JavaScript设计模式及代码实现——单例模式
    单例模式1定义保证一个类仅有一个实例,并提供一个访问它的全局访问点。2应用时机当一个类的实例被频繁使用,如果重复创建这个实例,会无端消耗资源。比如dialog弹......
  • Cmake之深入理解find_package()的用法
    刚刚接触Cmake的时候,对于find_package的用法以及背后的原理经常一头雾水,官方文档比较晦涩难懂,网上的博客也都讲解的比较片面。这里通过实战代码案例进行一下详细的总结......
  • 图数据库入门教程(一)简单理解图数据库
    以下内容是个人的理解,一家之言,可能误导,但能入门为什么会有图数据库?作为研发,我们接触最多的当属关系型数据库:Mysql、Oracle,还有一些非关系型数据库:MongoDB、Redis等,再广......
  • Golang 中反射的应用与理解
    Golang中反射的应用与理解https://mp.weixin.qq.com/s/TmzV2VTfkE8of2_zuKa0gAGolang中反射的应用与理解原创 赵燕辉 字节跳动技术团队 2022-08-2312:00 发表于......