js 闭包

116人阅读 评论(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
查看评论

js闭包的理解以及闭包中this的理解

javascript 闭包、this 2016-01-25 js pl 闭包其实很好理解,但是由于经常把this和闭包绑在一起,从而加大了理解的难度,如果将他们分开考虑,那就清晰多...
  • u010585120
  • u010585120
  • 2016-07-27 16:59:54
  • 4960

javascript递归与闭包

转自Javascript高级程序设计(第三版): 定义函数的方法有两种: 一种是函数声明,另一种是函数表达式。 关于函数声明,最重要的特征就是:函数声明提升(function declaration ...
  • u013250416
  • u013250416
  • 2015-08-13 10:28:47
  • 543

JS-闭包详解

闭包是JS中的一块硬骨头-不好啃,需要我们慢慢去咀嚼才能体会出其中的味道,嚼的不好,一不小心还容易崩牙!今天就让我们好好来咀嚼下这块硬骨头把!!! 1.什么是闭包? 所谓闭包:在一个函数作用域中 保留...
  • u014205965
  • u014205965
  • 2015-05-23 20:24:12
  • 1289

js事件参数和闭包

首先做事件参数 我们经常这样写   a.onload = function(){alert("df")); 这是不带参数的写法 如果带参数 a.onload= function(i){al...
  • zb219
  • zb219
  • 2012-05-25 15:31:48
  • 3415

js 使用闭包实现单例

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

js 函数的参数 问题 arguments对象 及闭包

js 参数的传递  是按值传递,在函数内部对变量所做的操作,不会影响到外部的变量。但是如果传递的是复合类型的对象,在内部对其属性所做的操作,则会影响外部对象,这是按址传递。 例如 var ...
  • tustyao
  • tustyao
  • 2015-06-27 23:35:45
  • 955

JavaScript原型、闭包、继承和原型链等等总结

几年之前学习过Javascript,当时学得比较浅显,现在又开始学了,发现Javascript其实挺难的,有些地方还是得花时间去理解的,于是看了很多的视频和博客,自己在这里小小的总结下。。。 1.一切...
  • Ocean111best
  • Ocean111best
  • 2016-09-17 21:10:38
  • 3089

js闭包的用途

我们来看看闭包的用途。事实上,通过使用闭包,我们可以做很多事情。比如模拟面向对象的代码风格;更优雅,更简洁的表达出代码;在某些方面提升代码的执行效率。1 匿名自执行函数我们知道所有的变量,如果不加上v...
  • sunlylorn
  • sunlylorn
  • 2011-06-09 17:25:00
  • 71885

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

除了模拟类的私有变量和私有方法。闭包还可用来模拟类的静态变量和方法。 除了再次利用js的闭包特性,还需要借助js语法上的一些特点。看下面一段代码: var MyNamespace ...
  • joyous
  • joyous
  • 2016-05-21 13:46:39
  • 850

JavaScript之闭包问题以及立即执行函数

JavaScript的立即执行函数以及闭包问题。
  • sinat_35512245
  • sinat_35512245
  • 2016-12-08 10:38:42
  • 3216
    个人资料
    持之以恒
    等级:
    访问量: 1万+
    积分: 321
    排名: 24万+
    最新评论