说到闭包,大部分的初始者,都是谈虎色变的。最近对闭包,有了自己的理解,就感觉。其实我们误解闭包。也被网上各种说的闭包的解释给搞迷糊。

一句话:要想理解一个东西还是看权威的东西。

下面我来通俗的讲解一个闭包的知识。(建议大家去读JavaScript权威指南)

我们先弄明白几个问题:

1、作为命名空间的函数:

在函数中声明的变量在整个函数体内都是可见(包括嵌套的函数)在函数的外部不是可见的。不在任何函数内声明的是全局变量

===》也就是说:一个函数它就是一个作用域,不管你里面有什么东西。他们都是一家子。

function fn(){

  var b1,b2.....;

  function a1(){}

  function a2(){}

  ..........//不管你是有多少函数,多少变量。你们都被fn用{}包围着,那么你们在fn下都是相互透明的。

}

2、函数只有在调用的时候,才会执行,函数名是函数的引用。(说白了就是在函数名的后面加个括号呗)

 function fn(){

    alert("调用我,我才会alert")

  }

fn()//在函数名的后面加了一个()这个函数才会执行。===============这点大家肯定很明白的吧

3、函数本身也是一个对象:(JavaScript中一切皆是对象,{个别的特例,咱暂且不说})

  对象:可以有属性 、方法。对象的内的方法调用自己的属性,=============这个大家也肯定没有问题吧

  也就是说,一个对象的内部是一家族。

  var obj ={

  var name;

  function getName(){}// getName() 方法和name属性,都是在obj这个对象的作用域内的==========其实就是上面1所称述的那样。

}

  

好了,如果你理解,上面这三个知识点,你可以继续看下面的了。【问问自己理解这三个知识点没????????????????????】

闭包

JavaScript权威指南中有一段关于闭包的话。

函数的执行依赖于变量的作用域,这个作用域是在函数定义时决定的,而不是函数调用时决定的。

总结:函数体内的变量都可以保存在这个函数的的作用域内。这种特性在计算机科学内叫做闭包

这是一个很正常的东西啊。一个函数圈了一个作用域,然后一些代码,在我的区域里面保存了。不就是我的作用域下的吗?

就像:

  function a(){

    function b(){}

}

不要告诉,现在的b是属于 外人的。就像上文1说的那样,a这个函数是一个命名空间,一个作用域。在我的作用域里面的东西,怎么可能是别人的额。

===所以:在我作用域里面的,是我家的,可以拿我家的东西。(函数体内可以保存变量在这个函数的作用域。之所以说官方强调闭包,就是因为JavaScript函数内保存变量时,和其他语言,Java。。不太一样,有个作用域链等等。。。。不先管他们。)

======总之======【我们就理解为:闭包的特性的初衷就是在一个函数作用域内保存变量。一个狠狠正常的事情啊,我家的东西放我家啊,我爱我家】

例子:村子与张三家族的关系。

var area ="这是村里的东西";

function zhangjia(){
  var area ="这是张家的东西";
  function getArea(){
  return area;
  }
  return getArea();
}

zhangjia();            //这是张家的东西

如果我这样的话;

var area ="这是村里的东西";

function zhangjia(){
  var area ="这是张家的东西";
  function getArea(){
  return area;
  }
  return getArea;
}

var  getSomeArea = zhangjia();//返回的函数的引用,将此引用赋给一个变量,那么getSomeArea这个变量同样是引用张家的getArea方法啊。

getSomeArea();     //现在,调用这个方法(加())不就是调用张家的那个getArea吗。拿到的area还是张家的area啊。因为,在一个开始的时候,人家就是属于张家的,当然取张家的东西。

===============【函数的执行依赖于变量的作用域,这个作用域是在函数定义时决定的,而不是函数调用时决定的。】多好的理解,很正常的逻辑啊

但是但是,要说但是了,正式由于JavaScript闭包存储变量的特殊性,就会出现一些问题。

接着看:我们看看这个经常被网上的大神拿来用的一个例子。

var result=[];
function foo(){
  var i= 0;
  for (;i<3;i=i+1){
    result[i]=function(){
    alert(i)
    }
  }
};
foo();//foo是一个函数的引用,foo()就是调用这个函数,没有问题吧。
result[0](); // 3
result[1](); // 3
result[2](); // 3

为啥,为啥,为啥都是3 。

我们期望的是每次都把对应的i值alert出来。但是结果却是这样。

来:一个函数只要在调用的时候,才会执行。(熟悉不??????)

result[i] = function(){alert(i)} 这不就是把一个函数赋值给一个变量,这个变量装的是函数的引用,注意---就是引用,就像上面说的没有执行呢。

当我们执行的时候:

result[0]() -------发生 了什么?????????????????????????????????

????????????????

对啊,就是那个闭包的问题啊;方法会去自己家里拿i值。哪个家?????foo这个家里啊。这是时候的i是3 了。alert(i)不就是3了。

多么多么正常的正常的事 啊。狠狠正常的逻辑

解决呢??

有人说,既然你说没有执行,那我就立即执行,循环的时候就执行,不光是一个引用在那里。。。

。。。。好,聪明

var result=[];
function foo(){
  var i= 0;
  for (;i<3;i=i+1){
    result[i]=(function(){
      alert(i);
    })();//立即执行,返回的是一个结果给result ,不是引用了。
  }
};
foo();

如果还想要result[i]()这种方式调用,咋办呢?

这个家族里的东西,你在拿到你的小家里去吧。在你家保存下

var result=[];
function foo(){
    var i= 0;
    for (;i<3;i=i+1){
      result[i]=(function(j){
        return function(){
        alert(j)
        }
      })(i);//作为一个参数传到小家去,虽然现在result[i]还是一个引用,引用一个函数,但是这个函数保存了每次循环时的对应的i值。
  }
};
foo();

result[1] //1

综上所述:

  闭包本来就是一个很正常的逻辑。但是由于他的实现方式涉及作用域链,作用域之间的引用问题,显得他很难理解。

  希望带着我说的额这些,多去理解一下。你发现,人家本来就是一个很正常的逻辑问题:我爱我家啊。。。。。。。。。。。

那些年,我们误解的 JavaScript 闭包的更多相关文章

  1. 什么是JavaScript闭包终极全解之一——基础概念

    本文转自:http://www.cnblogs.com/richaaaard/p/4755021.html 什么是JavaScript闭包终极全解之一——基础概念 “闭包是JavaScript的一大谜 ...

  2. 《Web 前端面试指南》1、JavaScript 闭包深入浅出

    闭包是什么? 闭包是内部函数可以访问外部函数的变量.它可以访问三个作用域:首先可以访问自己的作用域(也就是定义在大括号内的变量),它也能访问外部函数的变量,和它能访问全局变量. 内部函数不仅可以访问外 ...

  3. JavaScript 闭包深入浅出

    闭包是什么? 闭包是内部函数可以访问外部函数的变量.它可以访问三个作用域:首先可以访问自己的作用域(也就是定义在大括号内的变量),它也能访问外部函数的变量,和它能访问全局变量. 内部函数不仅可以访问外 ...

  4. JavaScript闭包(Closure)

    JavaScript闭包(Closure) 本文收集了多本书里对JavaScript闭包(Closure)的解释,或许会对理解闭包有一定帮助. <你不知道的JavsScript> Java ...

  5. Javascript闭包和C#匿名函数对比分析

    C#中引入匿名函数,多少都是受到Javascript的闭包语法和面向函数编程语言的影响.人们发现,在表达式中直接编写函数代码是一种普遍存在的需求,这种语法将比那种必须在某个特定地方定义函数的方式灵活和 ...

  6. javascript闭包理解

    //闭包理解一 function superFun(){ var _super_a='a'; function subfuc(){ console.log(_super_a); } return su ...

  7. Javascript闭包深入解析及实现方法

    1.什么是闭包 闭包,官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分.闭包的特点:1. 作为一个函数变量的一个引用,当函数返回时 ...

  8. javascript闭包和作用域链

    最近在学习前端知识,看到javascript闭包这里总是云里雾里.于是翻阅了好多资料记录下来本人对闭包的理解. 首先,什么是闭包?看了各位大牛的定义和描述各式各样,我个人认为最容易一种说法: 外部函数 ...

  9. JavaScript闭包深入解析

    for (var i=1; i<=5; i++) { setTimeout( function timer() { console.log( i ); }, i*1000 ); } --上面这段 ...

随机推荐

  1. 【Java例题】5.5 两个字符串中最长公共子串

    5. 查找两个字符串中含有的最长字符数的公共子串. package chapter5; import java.util.Scanner; public class demo5 { public st ...

  2. Of efficiency and methodology

    There are only too many articles and books which pertains to the discussion of efficiency and method ...

  3. 如何为 caddy 添写自定义插件

    如何为 caddy 添写自定义插件 项目地址:https://github.com/yhyddr/quicksilver/tree/master/gosample/caddy-plugin 前言 Ca ...

  4. Tunnel Warfare HDU - 1540 (线段树不同子树的合并)

    在抗日战争期间,华北平原广大地区进行了大规模的隧道战. 一般来说,通过隧道连接的村庄排成一列. 除了两端,每个村庄都与两个相邻的村庄直接相连. 入侵者经常对一些村庄发动袭击并摧毁其中的部分隧道. 八路 ...

  5. dart的基本语法(一)

    Hello world ​ 安装dart的环境就不赘述了,无脑安装就可以了,安装过程中好像需要梯子(vpn),我装的时候失败好多次,我的梯子不能用了,准备不装了的时候,莫名其妙的装好了.迷の操作.惯例 ...

  6. Android删除指定路径下指定前缀或后缀的文件

    微信公众号:CodingAndroid CSDN:http://blog.csdn.net/xinpengfei521声明:本文由CodingAndroid原创,未经授权,不可随意转载! 需求 我们在 ...

  7. vscode导入已存在的vue.js工程

    1.安装vue_cli 如果安装了npm,直接在命令行输入npm install -g vue-cli,安装在全局组件目录下 完成后,可以在命令测试下 2.导入工程 打开vscode-------&g ...

  8. 【模板】zkw线段树

    题意简述 已知一个数列,你需要进行下面两种操作: 1.将某一个数加上x 2.求出某区间每一个数的和 代码 #include <cstdio> using namespace std; in ...

  9. centos7单机安装kafka,进行生产者消费者测试

    [转载请注明]: 原文出处:https://www.cnblogs.com/jstarseven/p/11364852.html   作者:jstarseven    码字挺辛苦的.....  一.k ...

  10. 【hdu 2544最短路】【Dijkstra算法模板题】

    Dijkstra算法 分析 Dijkstra算法适用于边权为正的情况.它可用于计算正权图上的单源最短路( Single-Source Shortest Paths, SSSP) , 即从单个源点出发, ...