闭包,在一开始接触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——以简单的方式理解闭包的更多相关文章

  1. 用最简单的方式理解 IoC 控制反转

    思想引入 假设一个系统原先只设定有一个默认的方法去完成业务,这里举例这个原先设定开发的是 UserDaoImpl(可能有些牵强,但是不影响我们对逻辑的理解)这样一个业务. 后来有一天,需求变了,业务流 ...

  2. 最简单的方式理解Vue的自定义指令与混合

    vue.js 自定义指令 钩子函数:bindinsertedupdatecomponentUpdatedunbind 钩子函数完整实例:html: <div id="hook-argu ...

  3. 最简单的例子理解Javascript闭包

    理解Javascript的闭包非常关键,本篇试图用最简单的例子理解此概念. function greet(sth){ return function(name){ console.log(sth + ...

  4. JavaScript学习总结——我所理解的JavaScript闭包

    一.闭包(Closure) 1.1.什么是闭包? 理解闭包概念: a.闭包是指有权限访问另一个函数作用域的变量的函数,创建闭包的常见方式就是在一个函数内部创建另一个函数,也就是创建一个内部函数,创建一 ...

  5. JavaScript 从闭包可以做什么开始,将有助于理解闭包

    本文内容 函数内部访问全局变量 函数外部不能直接访问局部变量 函数外部访问局部变量 保护私有成员 持久性 模块化 抽象性 闭包是 JavaScript 的重要特性,非常强大,可用于执行复杂的计算,可并 ...

  6. javascript深入理解闭包

    一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量 ...

  7. javascript深入理解闭包(转)

    一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量 ...

  8. 【repost】让你一句话理解闭包(简单易懂)

    接触javascript很久了,每次理解闭包都似是而非,最近在找Web前端的工作,所以需要把基础夯实一下. 本文是参照了joy_lee的博客 闭包 在她这篇博客的基础上以批注的形式力争把我的理解阐述出 ...

  9. javascript花式理解闭包

    一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量 ...

随机推荐

  1. C++中关于指针初始化和使用NULL的理解

    1.严禁使用未被初始化的指针:C++创建指针的时候,只分配存储地址的内存,并不会分配存储数据的内存,所以指针可能指向任何位置. (1)使用解除运算符(*)之前,一定要对指针初始化,否则若声明的指针刚好 ...

  2. git中手动删除的文件如何在git中删除

    在日常开发中,我们可能或手动删除(delete键删除的)一些文件,然而我们本来应该是用git rm fileName命令删除的,但是现在我们手动删除了,那么要如何在git里面讲那些手动删除的文件删除呢 ...

  3. Android、iPhone和Java三个平台一致的加密工具

    先前一直在做安卓,最近要开发iPhone客户端,这其中遇到的最让人纠结的要属Java.Android和iPhone三个平台加解密不一致的问题. 因为手机端后台通常是用JAVA开发的Web Servic ...

  4. 自定义ShareDialog视图

    1. share_item.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayou ...

  5. 第一次,触碰Web App项目,栽过的那些坑。

    此项目是一个IPad上的Web App项目,页面的滚动用了最新的IScroll 5.0 插件, 确实是挺潮的. 项目用时 1个月 完成的, 准备今天晚上上线. 这是年前的最后一篇文章了,与众位博友分享 ...

  6. The resource could not be loaded because the App Transport

    Xcode7 beta 网络请求报错:The resource could not be loaded because the App Transport Xcode7 beta 网络请求报错:The ...

  7. angular依赖注入的理解(转)

    使用过java进行开发的人肯定知道大名鼎鼎的spring框架,对于spring的IOC肯定也有所了解,通过配置文件定义好bean之后,如果需要使用这些bean,不需要自己去实例化,而是跟spring这 ...

  8. 【字符串处理】HDOJ-1020-Encoding

    [题目链接:HDOJ-1020] 相邻字符,两两比较. #include<cstdio> #include<cstring> ; char sr[MAXN]; int main ...

  9. strleng函数和filterHtml函数的据悉

    紧接着“CKEditor如何统计文字数量”,我想稍微说下,下面就filterHtml就是用来过滤全部html标签的. /** *过滤html标签 */ function filterHtml(s){ ...

  10. ASP.NET MVC+Bootstrap个人博客之后台dataTable数据列表(五)

    jQuery  dataTables 插件是一个优秀的表格插件,是后台工程师的福音!它提供了针对数据表格的排序.浏览器分页.服务器分页.查询.格式化等功能.dataTables 官网也提供了大量的演示 ...