关闭

js 闭包

31人阅读 评论(0) 收藏 举报
分类:
author: 陈家宾(617822642@qq.com)
date: 2018-1-29

什么是闭包(closure)

在我们最通俗的理解里,闭包就是函数里反回函数,不过自从看了小绿书《JavaScript 权威指南》后,发现这个解释其实是错的

函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性在计算机科学文献中称为“闭包”。

从技术的角度讲,所有的 JavaScript 函数都是闭包:它们都是对象,它们都关联到作用域链。

——《JavaScript 权威指南》第 6 版,P182-P183

所以闭包本质上讲的是函数所包起来作用域(scope),所以闭包是作用域的深层次范畴。

那又为什么有“闭包就是函数里返回函数”的说法呢?

当调用函数时闭包所指向的作用域链和定义函数时的作用域链不是同一个作用域链时,事情就变得非常微妙。

——《JavaScript 权威指南》第 6 版,P183

所以应该说是闭包的特殊特性让他成为人们所熟知的 “闭包” 。

JavaScript 函数的执行用到了作用域链,这个作用域链是函数定义的时候创建的

也就是说定义函数的时候会创建一个作用域链,函数执行的时候会查询这个作用域链。在闭包情况下,也就是当函数 A 定义在函数 B 里时,函数 A 的作用域链就包含当前 B 包起来的作用域 b。

所以常说的 “闭包” 指的是函数 A 作用域链里这个特殊的作用域 b。(所以上下文讲的带双引号的 “闭包” 都是指待这种特殊场景下(函数里的函数)的闭包)

怎么实现 “闭包”

// demo1
function b() {
  var c = 1;
  return function a() {
    console.log(c);
  }
}
console.log(c); // error
b()(); // 1

demo1 就是一个简单的 “闭包” 的例子


闭包能干嘛

实现私有变量

demo1 也是一个私有变量的例子,在全局里不能访问变量 c ,用 b 函数实现的闭包可以访问局部变量 c

用法1:实现对多个元素循环添加事件(let 能简单解决这个问题,这里不做讨论)

  <ul>
      <li>1</li>
      <li>2</li>
      <li>3</li>
      <li>4</li>
  </ul>
  <script>
      var $lis = document.getElementsByTagName('li');
      for (var i=0; i<$lis.length; i++) {
          (function (i) {
              $lis[i].onclick = function () {
                  console.log(i);
              };
          })(i);
      }
  </script>

用法2:函数工厂

  function makeAdder(x) {
    return function(y) {
      return x + y;
    };
  }

  var add5 = makeAdder(5);
  var add10 = makeAdder(10);

  console.log(add5(2));  // 7
  console.log(add10(2)); // 12


闭包的副作用

  1. this 转移

    var name = "The Window";
    var object = {
    name : "My Object",
    getNameFunc : function(){
      return function(){
        return this.name;
      };
    }
    };
    alert(object.getNameFunc()()); // window

    this 对象是在运行时基于函数的执行环境绑定的()

    所以最保险的做法是将外部作用域中的 this 对象保存在一个装饰能够访问的变量里

    var name = 'The Window';
    var object = {
    name: 'My Object',
    getNameFunc: function () {
      var that = this;
      return function () {
        return that.name;
      }
    }
    }
    alert(object.getNameFunc()()); // "My Object"
  2. 内存泄露

    由于闭包作用域中保存着的元素无法被自动销毁,会导致内存泄露。因此,在有可能的情况下,还应记得手动销毁这个元素

    function assignHandler() {
     var element = document.getElementById('someElement');
     var id = element.id;
     element.onclick = function () {
       alert(id);
     };
     element = null;
    }

参考资料

  1. 《JavaScript 权威指南》第 6 版,David Flanagan 著,淘宝前端团队 译
  2. 《JavaScript 高级程序设计》第 3 版,Nicholas C.Zaks 著,李松峰 曹力 译
  3. MDN Web 文档,https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closuresszengtal, Dec 8, 2017, 6:25:49 AM
0
0
查看评论

关于js 的new 与闭包的实验

var Cu = function () { this.cc = 10; var call = function () {  alert(cc) }; return call; };         var cu =n...
  • zb219
  • zb219
  • 2012-09-01 11:18
  • 1332

JS之经典for循环闭包问题解决方法

JS之经典for循环闭包问题解决方法 像这样一个代码片段,初学者会理所当然地认为依次点击Li会弹出相应的0、1、2、3、4、5,但实际结果却是这样的 我们无论点哪个按钮,最后弹出来的都是6。经典的for循环闭包问题。 那么,首先让我们来了解一下什么是闭包,百度百科是这样解释的:闭包是可以包...
  • YuLi_Zoe
  • YuLi_Zoe
  • 2015-01-30 13:09
  • 6931

JS之匿名函数与闭包

匿名函数是指没有指定函数名称的函数,先来看下面的例子:想想看结果是什么?var a = function(t) { return t; } (1 + 2).toString(); alert(a); 这里就是定义了一个匿名函数,传入参数(1+2)并且执行,然后赋值给变量a。因为在第一行没有写分号...
  • kkdelta
  • kkdelta
  • 2013-01-07 16:37
  • 8275

使用模块化编程库和闭包使后台JS更加规范

1、问题及方案后台js代码规范度不好,怎么写的都有,不易维护、复用度低,我们不期全部使用backbone做到前端MVC,但使用模块化编程库做到模块化开发还是简单而有意义的。2、为什么要模块化时至今日,把脚本放在页面的底部,已不再是最佳的解决方案,甚至事与愿违,转化为性能的毒药。出于种种的原因,我们几...
  • ww_regou
  • ww_regou
  • 2016-08-19 14:08
  • 769

js 使用闭包封装数据

像c++/java等高级语言都提供了 private 关键字使得数据的访问私有化,但是js并没有提供这一功能,如何实现呢?我们可以使用闭包模拟实现。   function Student(param_name,param_age){ var m_name,m_age; ...
  • dai_jing
  • dai_jing
  • 2015-07-31 09:59
  • 1833

js 使用闭包实现单例

//闭包的使用 var c=(function a(){ var i=0; function b(){ return (++i); } return b; })(); console.log(c()); console.log(c()); //结...
  • dai_jing
  • dai_jing
  • 2015-07-27 11:59
  • 1374

js---闭包和面向对象编程

这两个概念理解起来不容易,翻查了很多资料,几乎耗费了我一天的时间来理解它,感觉自己都快走火入魔了。不过最终有所了悟,一番付出还是有所收获的。(1)闭包概念很多书上关于闭包的定义直接阅读的话很难理解,下面我通过实例来讲解这个概念。1、首先,我们必须了解变量的作用于问题。js的作用于无外乎有两种,一种是...
  • liuxuan12417
  • liuxuan12417
  • 2016-11-24 22:28
  • 724

js中的匿名函数和闭包总结篇

匿名函数就是没有名字的函数,闭包是可访问一个函数作用域里变量的函数。一.匿名函数//普通函数 function box() { //函数名是box return 'Lee'; }//匿名函数 function () { ...
  • u012896140
  • u012896140
  • 2015-10-29 17:50
  • 1183

Javascript 的函数式对象 利用闭包模拟类的静态变量和方法

除了模拟类的私有变量和私有方法。闭包还可用来模拟类的静态变量和方法。 除了再次利用js的闭包特性,还需要借助js语法上的一些特点。看下面一段代码: var MyNamespace = {}; // 定义命名空间 MyNamespace.TreeItem = (funct...
  • joyous
  • joyous
  • 2016-05-21 13:46
  • 794

用9种办法解决 JS 闭包经典面试题之 for 循环取 i

闭包 正确的说,应该是指一个闭包域,每当声明了一个函数,它就产生了一个闭包域(可以解释为每个函数都有自己的函数栈),每个闭包域(Function 对象)都有一个 function scope(不是属性),function scope内默认有个名为 Globe 的全局引用(有了这个引用,就可...
  • u013243347
  • u013243347
  • 2016-08-06 10:11
  • 2154
    个人资料
    • 访问:8983次
    • 积分:258
    • 等级:
    • 排名:千里之外
    • 原创:18篇
    • 转载:0篇
    • 译文:0篇
    • 评论:1条
    文章分类
    最新评论