欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

关于JS中闭包的问题

程序员文章站 2022-04-19 14:00:12
一直以来,我都以为我已经懂了JavaScript中 闭包 的概念,直到有一次小伙伴突然问我这个概念的时候,我才发现我根本不知道该怎来么跟他来讲述这个概念。 那时候我就知道我是自我欺骗,打肿脸充胖子了。 所以,花了点时间去专门了解了一下,今天专门记录一下自己所理解的闭包。 一. 概念 闭包,简单来讲, ......

一直以来,我都以为我已经懂了javascript中闭包的概念,直到有一次小伙伴突然问我这个概念的时候,我才发现我根本不知道该怎来么跟他来讲述这个概念。

那时候我就知道我是自我欺骗,打肿脸充胖子了。

所以,花了点时间去专门了解了一下,今天专门记录一下自己所理解的闭包。

一. 概念

闭包,简单来讲,就是定义在函数内部的函数,使用闭包,可以让你有权访问另一个函数作用域内的变量。

所以,想要了解闭包的前提是,你首先要知道在js中变量作用域的问题。

创建闭包的常见方式就是在函数内部去创建另一个函数:

function fun() {
    var variable = 'hello world';
    function inner() {
        console.log(variable);
    }
    return inner;
}

var outer = fun();
outer(); // hello world



在这个例子中,我们想在外部用到fun()中定义的variable的值,但是因为变量作用域的问题,我们不可能直接取到。

所以我们采取了变通的方法:在fun()函数内部又创建了一个函数inner(),这时fun()内部的variable对于inner()来说是可见的,既然inner()可以取到fun()中的变量,那么我们将inner()返回,就可以用到fun()中定义的variable了。

闭包在此处,就是链接函数内部和外部的一个桥梁。

在这里提一句:如果inner()内部存在新设置的变量,对于fun()函数来说是不可见的,此处涉及到js中作用链的问题,理解作用链对于彻底理解闭包的问题很有帮助,可以参考javascript高级程序设计(第四章)去了解一下作用链。

其实闭包的定义也就这么简单,对于那些过于抽象的定义,置之不理即可,不用强迫自己去理解那些比较晦涩难懂的专业定义,记住自己最终的目的并不是为了咬文嚼字,实用才是根本。

最后借用知乎上一个回答来形象的描述一下闭包的概念:

关于JS中闭包的问题

二. 闭包的用处

我总结的闭包主要用处:

  1. 让外部可以读取函数内部的变量。
  2. 可以封装对象的私有属性和私有方法。

第一点用处就是在说闭包概念时候所举的例子。

下面说下第二点用处:可以封装对象的私有属性和私有方法。

function worker(name) {
    var _salary;
    function setsalary(value) {
        _salary = value;
    }
    function getsalary() {
        return _salary;
    }
    
    return {
        name: name,
        setsalary; setsalary;
        getsalary: getsalary;
    }
}

var cxk = worker('cxk');
cxk.setsalare(100);
cxk.getsalary(); // 100



在上面的代码中,通过闭包,_salary变成了cxk的私有变量。

三. 需要注意的地方

第一点需要注意的地方是关于使用闭包时内存的问题,因为闭包会携带包含它的函数的作用域,因此会比其他的函数占用更多的内存,滥用闭包会造成网页的性能问题,所以对于闭包,建议只在绝对必要时在考虑使用。

对于闭包中垃圾回收的详细测试,参考。

第二点需要注意的就是在创建闭包时可能会常犯的错误:在循环中的闭包创建问题。

function createarray() {
  var result = [];
  for (var i = 0; i < 10; i++) {
    result[i] = function () {
      return i;
    }
  }
  return result;
}

var arr = createarray();
arr[1](); // 10
arr[2](); // 10



可以看到,跟我们预期达到的结果不一样,每一个位置上的函数都返回了10。

这是因为每一个result[i]上都保存着createarray()函数的活动对象(参考js中的作用链),而给result[i]进行赋值时,'function(){return i}'没有执行,所以最后在arr[1]运行时,返回的i其实都是同一个值,即最后生成的i,值为10。

可以做出如下修改。

修改一:在闭包里再添加一个闭包函数,同时立即执行。

function createarray() {
  var result = [];
  for (var i = 0; i < 10; i++) {
    result[i] = function (num) {
      return function () {
        return num;
      }
    }(i)
  }
  return result;
}

var arr = createarray();
arr[1]();



修改二:修改varlet

function createarray() {
  var result = [];
  for (let i = 0; i < 10; i++) {
    result[i] = function () {
      return i;
    }
  }
  return result;
}

var arr = createarray();
arr[1]();



以上就是我对闭包的比较浅显的认知,如果有不对的地方,希望能够指正,以免我误人子弟,谢谢。