深入理解javascript闭包(一)
闭包(closure)是Javascript语言的一个难点。也是它的特色,非常多高级应用都要依靠闭包实现。
一、什么是闭包?
官方”的解释是:闭包是一个拥有很多变量和绑定了这些变量的环境的表达式(一般是一个函数),因而这些变量也是该表达式的一部分。
相信非常少有人能直接看懂这句话,由于他描写叙述的太学术。事实上这句话通俗的来说就是:JavaScript中全部的function都是一个闭包。只是一般来说,嵌套的function所产生的闭包更为强大。也是大部分时候我们所谓的“闭包”。
要理解闭包,首先必须理解Javascript特殊的变量作用域。
二、变量的作用域
变量的作用域无非就是两种:全局变量和局部变量。
Javascript语言的特殊之处。就在于函数内部能够直接读取全局变量。
var n=999; function f1(){
alert(n);
} f1(); // 999
还有一方面,在函数外部自然无法读取函数内的局部变量。
function f1(){
var n=999;
} alert(n); // error
这里有一个地方须要注意,函数内部声明变量的时候。一定要使用var命令。假设不用的话,你实际上声明了一个全局变量!
function f1(){
n=999;
} f1(); alert(n); // 999
三、怎样从外部读取局部变量?
出于种种原因,我们有时候须要得到函数内的局部变量。可是,前面已经说过了,正常情况下,这是办不到的,仅仅有通过变通方法才干实现。
那就是在函数的内部,再定义一个函数。
function f1(){
n=999;
function f2(){
alert(n); // 999
}
}
在上面的代码中,函数f2就被包含在函数f1内部,这时f1内部的全部局部变量。对f2都是可见的。可是反过来就不行。f2内部的局部变量,对f1 就是不可见的。
这就是Javascript语言特有的“链式作用域”结构(chain scope),
子对象会一级一级地向上寻找全部父对象的变量。所以,父对象的全部变量。对子对象都是可见的,反之则不成立。
既然f2能够读取f1中的局部变量,那么仅仅要把f2作为返回值。我们不就能够在f1外部读取它的内部变量了吗。
function f1(){ n=999; function f2(){
alert(n);
} return f2; } var result=f1(); result(); // 999
上面代码中的f2函数,就是闭包。
各种专业文献上的“闭包”(closure)定义非常抽象,非常难看懂。我的理解是。闭包就是可以读取其它函数内部变量的函数。
因为在Javascript语言中。仅仅有函数内部的子函数才干读取局部变量,因此能够把闭包简单理解成“定义在一个函数内部的函数”。
所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
四、闭包的用途
闭包能够用在很多地方。它的最大用处有两个,一个是前面提到的能够读取函数内部的变量。还有一个就是让这些变量的值始终保持在内存中。
怎么来理解这句话呢?请看以下的代码。
function f1(){ var n=999; nAdd=function(){n+=1} function f2(){
alert(n);
} return f2; }
var result=f1();
result(); // 999
nAdd();
result(); // 1000
在这段代码中,result实际上就是闭包f2函数。它一共执行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中。并没有在f1调用后被自己主动清除。
为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中。而f2的存在依赖于f1,因此f1也始终在内存中。不会在调用结束后,被垃圾回收机制(garbage collection)回收。
这段代码中还有一个值得注意的地方,就是“nAdd=function(){n+=1}”这一行,首先在nAdd前面没有使用varkeyword。因此 nAdd是一个全局变量,而不是局部变量。
其次。nAdd的值是一个匿名函数(anonymous function)。而这个
匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,能够在函数外部对函数内部的局部变量进行操作。
五、使用闭包的注意点
1)因为闭包会使得函数中的变量都被保存在内存中。内存消耗非常大,所以不能滥用闭包。否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量所有删除。
2)闭包会在父函数外部。改变父函数内部变量的值。
所以,假设你把父函数当作对象(object)使用。把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便
改变父函数内部变量的值。
六、思考题
假设你能理解以下代码的执行结果。应该就算理解闭包的执行机制了。
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()()); //The Window
七、JavaScript闭包样例
function outerFun()
{
var a=0;
function innerFun()
{
a++;
alert(a);
}
}
innerFun() //上面的代码是错误的.innerFun()的作用域在outerFun()内//部,所在outerFun()外部调用它是错误的. //改成例如以下,也就是闭包: function outerFun()
{
var a=0;
function innerFun()
{
a++;
alert(a);
}
return innerFun; //注意这里
}
var obj=outerFun();
obj(); //结果为1
obj(); //结果为2
var obj2=outerFun();
obj2(); //结果为1
obj2(); //结果为2
再次来看什么是闭包?
当内部函数 在定义它的作用域 的外部 被引用时,就创建了该内部函数的闭包 ,假设内部函数引用了位于外部函数的变量,当外部函数调用完成后,这些变量在内存不会被 释放,由于闭包须要它们。
再来看一个样例
function outerFun()
{
var a =0;
alert(a);
}
var a=4;
outerFun();
alert(a);
结果是 0 , 4 . 由于在函数内部使用了varkeyword 维护a的作用域在outFun()内部.
再看以下的代码:
unction outerFun()
{
//没有var
a =0;
alert(a);
}
var a=4;
outerFun();
alert(a);
结果为 0 , 0 真是奇怪,为什么呢?
作用域链是描写叙述一种路径的术语,沿着该路径能够确定变量的值 .当运行a=0时,由于没有使用varkeyword,因此赋值操作会沿着作用域链到var a=4; 并改变其值.
假设你对javascript闭包还不是非常理解,能够再看下篇文章。
深入理解javascript闭包(一)的更多相关文章
- 我从来不理解JavaScript闭包,直到有人这样向我解释它...
摘要: 理解JS闭包. 原文:我从来不理解JavaScript闭包,直到有人这样向我解释它... 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 正如标题所述,JavaScript闭包 ...
- 深入理解JavaScript闭包【译】
在<高级程序设计>中,对于闭包一直没有很好的解释,在stackoverflow上翻出了一篇很老的<JavaScript closure for dummies>(2016)~ ...
- 【转】深入理解JavaScript闭包闭包(closure) (closure)
一.什么是闭包?"官方"的解释是:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分.相信很少有人能直接看懂这句话,因为他描述 ...
- 全面理解Javascript闭包和闭包的几种写法及用途
好久没有写博客了,过了一个十一长假都变懒了,今天总算是恢复状态了.好了,进入正题,今天来说一说javascript里面的闭包吧!本篇博客主要讲一些实用的东西,主要将闭包的写法.用法和用途. 一.什么 ...
- 深入理解JavaScript闭包(closure)
最近在网上查阅了不少javascript闭包(closure)相关的资料,写的大多是非常的学术和专业.对于初学者来说别说理解闭包了,就连文字叙述都很难看懂.撰写此文的目的就是用最通俗的文字揭开Java ...
- 深入理解javascript闭包(一)
原文转自脚本之家(http://www.jb51.net/article/24101.htm) 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. ...
- 深入理解Javascript闭包概念
一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部能够直接读取全局变量 ...
- 轻松理解JavaScript闭包
摘要 闭包机制是JavaScript的重点和难点,本文希望能帮助大家轻松的学习闭包 一.什么是闭包? 闭包就是可以访问另一个函数作用域中变量的函数. 下面列举出常见的闭包实现方式,以例子讲解闭包概念 ...
- 【译】理解JavaScript闭包——新手指南
闭包是JavaScript中一个基本的概念,每个JavaScript开发者都应该知道和理解的.然而,很多新手JavaScript开发者对这个概念还是很困惑的. 正确理解闭包可以帮助你写出更好.更高效. ...
随机推荐
- Fedora 18 安装前指南
Secure Boot 与 Win 8 随着 Win8 的发布,先前关于 Secure Boot 和 UEFI 的诸多猜测也得到了证实,Fedora 18 也将如同当初计划的那样使用 shim + ...
- Mysql访问 for橙子小海
package com.mvc.model.dao; import com.mvc.model.daoutil.DBConn; import com.mvc.model.entity.Blog; 这是 ...
- 阻止文件不被上传到iCloud-b
有空用下 http://www.cocoachina.com/bbs/read.php?tid=86244 http://www.ooso.net/archives/617 http://blog.c ...
- hadoop 2.2.0 集群部署 坑
注意fs.defaultFS为2..0新的变量,代替旧的:fs.default.name hadoop 2.2.0 集群启动命令:bin/hdfs namenode -formatsbin/start ...
- [BZOJ 1875] [SDOI 2009] HH去散步【矩阵乘法】
题目链接:BZOJ - 1875 题目分析: 这道题如果去掉“不会立刻沿着刚刚走来的路走回”的限制,直接用邻接矩阵跑矩阵乘法就可以了.然而现在加了这个限制,建图的方式就要做一些改变.如果我们把每一条边 ...
- ConnectifyHotspotInstaller3.7注册码
ConnectifyHotspotInstaller3.7注册码 邮箱: wcxu21@126.com 密 钥:QEX4HR-9VLS2N-AXFA3A-K8CD8M-1DQ7Q1-CCDDTB-KL ...
- 模拟I2C从机程序
;Slave.asm SCL BIT P1. SDA BIT P1. ;---------------------------- ORG RESET: SETB SCL SETB SDA CALL I ...
- 转:我终于离开了年薪30w的IT行业
题目乍看起来有点故意惹人眼球的味道,但是对于我事实就是如此,暂且请君听我细细道来! 先自曝家门,我03年毕业,05年来深,06年买车子,06年底结婚,07年买了房子,09年生了儿子,妻子.房 ...
- [置顶] export命令-linux
export 命令 功能说明: 设置或显示环境变量. 语 法: export [-fnp][变量名称]=[变量设置值] 补充说明: 在shell中执行程序时,shell会提供一组环境变量. expor ...
- Linux&shell之Shell脚本
写在前面:案例.常用.归类.解释说明.(By Jim) 使用多条命令shell脚本的关键是可以输入多条命令,甚至可以将一条命令的结果传递给另一条命令.date;who(两个命令shell脚本的写法) ...