JavaScript——以简单的方式理解闭包
闭包,在一开始接触JavaScript的时候就听说过。首先明确一点,它理解起来确实不复杂,而且它也非常好用。那我们去理解闭包之前,要有什么基础呢?我个人认为最重要的便是作用域(lexical scope),如果对作用域和作用域链不理解的同学最好自己先去学一学,再回过头来,理解闭包,就更加轻松。
下面便直接进入主题。
我们知道一个函数是有作用域的,在函数内部定义的局部变量只有在函数内部才可以访问的到。一旦函数访问结束被销毁,局部变量随之也会销毁,无法通过任何方式再次访问局部变量,除了闭包。也就是说,我们可以通过闭包这一个方法,从函数的外部去访问到函数内部的变量,即使那个函数已经被销毁。没错,闭包最重要的用法就是,我们只提供某些接口去访问和修改局部变量,而外部是不能直接访问到局部变量的。
说了那么多有关如何使用闭包,我们来看看闭包是长什么样子的。又到了举个栗子的环节,依然是最简单的people和name。
var people = function(){
var name = "Yika";
var sayName = function(){
return name; //访问了people函数的局部变量name
}
var setName = function(newName){
name = newName; //访问了people函数的局部变量name
}
return{
sayName: sayName,
setName: setName
}//返回一个对象
}
var p1 = people(); //函数return的是一个对象,这个对象里有两个函数sayName和setName
console.log(p1.name); //undefined. name是people函数里的局部变量,而不是p1对象的属性,当然为undefined
console.log(p1.sayName());//"Yika"
p1.setName("Ruyi"); //通过setName函数修改局部变量name的值
console.log(p1.sayName());//"Ruyi"
看完这个例子,想必对闭包多少有个了解啦,除了注释的内容,下面再做些补充。
问:为什么局部变量name属性在people执行完之后,没有被销毁呢,反而数值还保存在内存中。
答: 在例子中,函数注释那里专门写了(访问了people函数的局部变量name)。正是因为people函数里的sayName函数和setName函数访问了name属性,并且通过return传到了p1对象里,成了p1的两个方法。因为方法一直引用着people函数的局部变量,所以不会被消除,依然会在内存中。这样便形成了闭包,可以在函数外部访问到函数内部的局部变量。
对此,我们可以换个更直观的写法。
var people = function(){
var name = "Yika";
var obj = {
sayName: function(){
return name;
},
setName: function(newName){
name = newName
}
};
return obj; //直观的返回对象
}
//下面的结果是一样的。
当然闭包也不是一直那么好用,特别是在循环里。继续举例子
<body>
<input type="button"/>
<input type="button"/>
<input type="button"/>
<input type="button"/>
<input type="button"/>
<input type="button"/>
<input type="button"/>
<script type="text/javascript">
var oBtn = document.getElementsByTagName('input');
for(var i = 0, len = oBtn.length; i < len; i++){
oBtn[i].onclick = function(){
alert("value = " + i); //闭包陷阱的发生地!永远输出 value = 7
}
}
</script>
</body>
当我们运行上面的代码的时候,我们是这样想的,循环一下按钮,并输出按钮所在的序号,但是我们得到的却永远是7。其实用我们之前讲的闭包会让变量的值一直保存在内存中的原理想一想,就应该懂了。当我们循环的时候按钮的点击事件时,是引用了for循环里的 i 变量。当所有按钮都绑定了点击事件后,i 的值也已经变成了7,当然所有的按钮输出的都是7啦!怎么解决这个问题也很好办的,但是我希望留下给大家思考。这里就说一下大致思路吧,我们可以在循环之外创建一个辅助函数,并让辅助函数return一个绑定当前 i 的函数。
当然这里我也只是抛砖引玉的介绍了一下闭包,希望可以帮到大家浅显简单的了解闭包。
还是那句话噢,有问题立即指正,我一定会立马检查更正,以免误导了大家!
JavaScript——以简单的方式理解闭包的更多相关文章
- 用最简单的方式理解 IoC 控制反转
思想引入 假设一个系统原先只设定有一个默认的方法去完成业务,这里举例这个原先设定开发的是 UserDaoImpl(可能有些牵强,但是不影响我们对逻辑的理解)这样一个业务. 后来有一天,需求变了,业务流 ...
- 最简单的方式理解Vue的自定义指令与混合
vue.js 自定义指令 钩子函数:bindinsertedupdatecomponentUpdatedunbind 钩子函数完整实例:html: <div id="hook-argu ...
- 最简单的例子理解Javascript闭包
理解Javascript的闭包非常关键,本篇试图用最简单的例子理解此概念. function greet(sth){ return function(name){ console.log(sth + ...
- JavaScript学习总结——我所理解的JavaScript闭包
一.闭包(Closure) 1.1.什么是闭包? 理解闭包概念: a.闭包是指有权限访问另一个函数作用域的变量的函数,创建闭包的常见方式就是在一个函数内部创建另一个函数,也就是创建一个内部函数,创建一 ...
- JavaScript 从闭包可以做什么开始,将有助于理解闭包
本文内容 函数内部访问全局变量 函数外部不能直接访问局部变量 函数外部访问局部变量 保护私有成员 持久性 模块化 抽象性 闭包是 JavaScript 的重要特性,非常强大,可用于执行复杂的计算,可并 ...
- javascript深入理解闭包
一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量 ...
- javascript深入理解闭包(转)
一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量 ...
- 【repost】让你一句话理解闭包(简单易懂)
接触javascript很久了,每次理解闭包都似是而非,最近在找Web前端的工作,所以需要把基础夯实一下. 本文是参照了joy_lee的博客 闭包 在她这篇博客的基础上以批注的形式力争把我的理解阐述出 ...
- javascript花式理解闭包
一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量 ...
随机推荐
- C# 计时器的三种使用方法
在.net中有三种计时器,一是System.Windows.Forms命名空间下的Timer控件,它直接继承自Componet;二是System.Timers命名空间下的Timer类. Timer控件 ...
- HDU 4717 The Moving Points(三分)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4717 题意:给出n个点的坐标和运动速度(包括方向).求一个时刻t使得该时刻时任意两点距离最大值最小. ...
- VS2015中快捷注释代码块
注释ctrl+k ctrl+c 反注释ctrl+k ctrl+u 需要注意的是第二个ctrl不能省略的
- 使用截图方式将Excel导出为PNG图片的不可行性
博主前面一篇文章使用了JAVA的Robot机制 模拟打开Excel然后Robot移动到指定区域,截图并生成PNG格式图片 试图使用这种方式将复杂的Excel报表转化成无差别的PNG图片 但是这种方式遇 ...
- QSettings读写注册表、配置文件
简述 一般情况下,我们在开发软件过程中,都会缓存一些信息到本地,可以使用轻量级数据库sqlite,也可以操作注册表.读写配置文件. 关于QSettings的使用前面已经介绍过了,比较详细,见" ...
- org.tigris.subversion.javahl.ClientException: Attempted to lock an already-locked dir异常解决方法
myeclipse用svn提交的时候报错: Attempted to lock an already-locked dir svn: Working copy 'D:/Program Files/My ...
- UVa 1328 (KMP求字符串周期) Period
当初学KMP的时候也做过这道题,现在看来还是刘汝佳的代码要精简一些,毕竟代码越短越好记,越不容易出错. 而且KMP的递推失配函数的代码风格和后面的Aho-Corasick自动机求失配函数的代码风格也是 ...
- Google发布SSLv3漏洞简要分析报告
今天上午,Google发布了一份关于SSLv3漏洞的简要分析报告.根据Google的说法,该漏洞贯穿于所有的SSLv3版本中,利用该漏洞,黑客可以通过中间人攻击等类似的方式(只要劫持到的数据加密两端均 ...
- ElasticSearch Remote Code Execution (CVE-2014-3120)
Elasticsearch is a powerful open source search and analytics engine. The vulnerability allows attack ...
- ASP.NET MVC 传值方法ViewData与ViewBag的区别
一.介绍 在Asp.net MVC 3 web应用程序中,我们会用到ViewData与ViewBag,对比一下: ViewData ViewBag 它是Key/Value字典集合 它是dynamic类 ...