那些年,我们误解的 JavaScript 闭包
说到闭包,大部分的初始者,都是谈虎色变的。最近对闭包,有了自己的理解,就感觉。其实我们误解闭包。也被网上各种说的闭包的解释给搞迷糊。
一句话:要想理解一个东西还是看权威的东西。
下面我来通俗的讲解一个闭包的知识。(建议大家去读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 闭包的更多相关文章
- 什么是JavaScript闭包终极全解之一——基础概念
本文转自:http://www.cnblogs.com/richaaaard/p/4755021.html 什么是JavaScript闭包终极全解之一——基础概念 “闭包是JavaScript的一大谜 ...
- 《Web 前端面试指南》1、JavaScript 闭包深入浅出
闭包是什么? 闭包是内部函数可以访问外部函数的变量.它可以访问三个作用域:首先可以访问自己的作用域(也就是定义在大括号内的变量),它也能访问外部函数的变量,和它能访问全局变量. 内部函数不仅可以访问外 ...
- JavaScript 闭包深入浅出
闭包是什么? 闭包是内部函数可以访问外部函数的变量.它可以访问三个作用域:首先可以访问自己的作用域(也就是定义在大括号内的变量),它也能访问外部函数的变量,和它能访问全局变量. 内部函数不仅可以访问外 ...
- JavaScript闭包(Closure)
JavaScript闭包(Closure) 本文收集了多本书里对JavaScript闭包(Closure)的解释,或许会对理解闭包有一定帮助. <你不知道的JavsScript> Java ...
- Javascript闭包和C#匿名函数对比分析
C#中引入匿名函数,多少都是受到Javascript的闭包语法和面向函数编程语言的影响.人们发现,在表达式中直接编写函数代码是一种普遍存在的需求,这种语法将比那种必须在某个特定地方定义函数的方式灵活和 ...
- javascript闭包理解
//闭包理解一 function superFun(){ var _super_a='a'; function subfuc(){ console.log(_super_a); } return su ...
- Javascript闭包深入解析及实现方法
1.什么是闭包 闭包,官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分.闭包的特点:1. 作为一个函数变量的一个引用,当函数返回时 ...
- javascript闭包和作用域链
最近在学习前端知识,看到javascript闭包这里总是云里雾里.于是翻阅了好多资料记录下来本人对闭包的理解. 首先,什么是闭包?看了各位大牛的定义和描述各式各样,我个人认为最容易一种说法: 外部函数 ...
- JavaScript闭包深入解析
for (var i=1; i<=5; i++) { setTimeout( function timer() { console.log( i ); }, i*1000 ); } --上面这段 ...
随机推荐
- .Net异步编程详解入门
前言 今天周五,早上起床晚了.赶着挤公交上班.但是目前眼前有这么几件事情.刷牙洗脸.泡牛奶.煎蛋.在同步编程眼中.先刷牙洗脸,然后烧水泡牛奶.再煎蛋,最后喝牛奶吃蛋.毫无疑问,在时间紧促的当下.它完了 ...
- GDOI#348大陆争霸[SDOI2010]最短路有限制条件
在一个遥远的世界里有两个国家:位于大陆西端的杰森国和位于大陆东端的 克里斯国.两个国家的人民分别信仰两个对立的神:杰森国信仰象征黑暗和毁灭 的神曾·布拉泽,而克里斯国信仰象征光明和永恒的神斯普林·布拉 ...
- CMake入门-02-HelloWorld扩展
工作环境 系统:macOS Mojave 10.14.6 CMake: Version 3.15.0-rc4 Hello,World! 扩展-同一目录,多个源文件 (1) 新建 hello 目录,创建 ...
- 《机器学习技法》---AdaBoost算法
1 AdaBoost的推导 首先,直接给出AdaBoost算法的核心思想是:在原数据集上经过取样,来生成不同的弱分类器,最终再把这些弱分类器聚合起来. 关键问题有如下几个: (1)取样怎样用数学方式表 ...
- JVM(十一):内存分配
JVM(十一):内存分配 在前面的章节中,我们花了大量的篇幅去介绍 JVM 内的内存布局.对象在内存中的状态.垃圾回收的算法和具体实现等.今天让我们探讨一下对象是如何分配内存的. 堆内存划分 前面说过 ...
- 小白学Python(4)——用Python创建PPT
python-pptx是一个用于创建和更新PowerPoint(.pptx)文件的Python库. 典型的用途是从数据库内容生成自定义的PowerPoint演示文稿,可通过单击Web应用程序中的链接进 ...
- Linux下Kafka下载与安装教程
原文链接:http://www.studyshare.cn/software/details/1176/0 一.预备环境 Kafka是java生态圈中的一员,运行在java虚拟机上,按Kafka官方说 ...
- 《NVM-Express-1_4-2019.06.10-Ratified》学习笔记(1)
材料说明: 文档<NVM-Express-1_4-2019.06.10-Ratified.pdf>来自于NVMe网站:https://nvmexpress.org/ 笔记目的是学习NVMe ...
- 使用maven搭建ssm框架环境
1.前言 因为经常换环境,在搭ssm框架的时候老是出错,所以记录一下最近搭建的环境,以供参考. 本文讲解如何使用maven搭建ssm框架,并能用于简单的登录注册. IDE:IDEA,JDK版本:1.8 ...
- 深度学习环境搭建部署(DeepLearning 神经网络)
工作环境 系统:Ubuntu LTS 显卡:GPU NVIDIA驱动:410.93 CUDA:10.0 Python:.x CUDA以及NVIDIA驱动安装,详见https://www.cnblogs ...