Javascript的闭包及其使用技巧实例
Javascript的闭包及其使用技巧实例
一、闭包的基本概念
闭包(Closure)是一个引用了自由变量的函数,记录了该函数在定义时的scope chain。又称词法闭包(Lexical Closure)或函数闭包(function closures).
闭包的基本规则:
* 函数执行是基于函数定义时的scope, 而不是 函数运行时的scope
(定义时的Scope: 在定义这个函数的时候的scope chain)
为此, JS的function对象的内部状态,不仅包括函数代码本身, 而且包括了一个引用,指向函数定义时的scope Chain,
后者,用于提供函数中变量的值, 这种把代码及其所需要的scope组合到一起, 就是 闭包,closure。它是JS许多实用技巧的技术基础。
二、闭包的应用实例
示例1:
var who = "global scope"; // 全局变量who
function checkscope() {
var who = "local scope"; // 局部变量who
function f() { return who; } // 嵌套函数,
return f();
}
checkscope(); // => "local scope"
f函数在定义的时候, scope chain中有局部变量who和全局变量who, 按照局部变量优先于全局变量的原则,
函数中的who的应该局部变量这的who,其值是 “local scope”。
这就是函数的定义时Scope。根据Clouse的特性,JS会记录这些信息, 不论这个函数f在什么地方执行, who的值都是这个“local scope”
示例2:执行的地方变了, 但是函数定义时的scope未变
var who = "global scope"; // A global variable
function checkscope() {
var who = "local scope"; // A local variable
function f() { return who; } // Return the value in scope here
return f;
}
checkscope()() // => "local scope", 虽然,在这个时候“运行时的scope”中的who已经是全局的了。
实例3: 定义一个函数, 每调用一次, 获取一个唯一的整数,而且从0开始递增,每次+1。
var uniqueInteger = (function() { // 定义并执行1个外层函数。
var counter = 0; // 根据“定义时的scope”原则, 这个变量事实上成了下面函数的私有变量, 虽然它在函数体外,
当外层函数返回的时候, 此变量只能被下面的嵌套函数存取,
return function() { return counter++; }; // 定义一个函数,称作嵌套函数,被输出给uniqueInteger,在外面使用, 不是在外层函数内使用。
}());
uniqueInteger(); // 0
uniqueInteger(); // 1
uniqueInteger(); // 2
uniqueInteger(); // 3
实例4: 带有reset的计数器
function Counter() { // 定义并执行1个外层函数。
var n = 0; // 根据“定义时的scope”原则, 这个变量事实上成了下面2个嵌套函数的私有变量, 虽然它在函数体外,
当外层函数返回的时候, 此变量只能被下面的嵌套函数存取,
return { // 定义2个嵌套函数,并组合成1个对象输出, 供外面使用;
// 这两个嵌套函数, 都可以存取外层函数中的局部变量n
count: function() { return n++; }; 。
reset: function() { n = 0; }
}
};
var counter1 = Counter(), // 每一次调用 外层函数Counter(),都创建1个新的scope chain和1个新的私有变量n,互相不影响
counter2 = Counter();
counter1.count(); // 0
counter1.count(); // 1
counter1.count(); // 2
counter2.count(); // 0
counter2.count(); // 1
counter2.count(); // 2
counter1.reset();
counter1.count(); // 0
counter1.count(); // 1
counter2.count(); // 3
counter2.count(); // 4
实例5: 与Ajax调用配合使用, 显示加载的过程和结果
<div></div>
<script src="jquery.js"></script>
<script>
var elem = jQuery("div");
elem.html("Loading...");
jQuery.ajax({
url: "test.html",
success: function(html){ //嵌入函数, 直接使用外层函数中的elem, 暴露给Ajax作为callback使用
assert( elem, "The element to append to, via a closure." );
elem.html( html );
}
});
</script>
实例6: 与timer配合使用, 显示动画
<div id="box" style="position:absolute;">Box!</div>
<script>
var elem = document.getElementById("box");
var count = 0;
var timer = setInterval(function(){ //嵌入函数, 直接使用外层函数中的elem和count, 暴露给Timer作为callback使用
if ( count < 100 ) {
elem.style.left = count + "px";
count++;
} else {
clearInterval( timer );
}
}, 10);
</script>
进阶: JS 引擎内部是如何实现Scope Chain和Clouse的?
Scope Chain是一个list, 不是stack,
当执行function的时候, 建立1个新scope object,来存储此函数中的局部变量,并且把这个object加入到scope chain中,
当推出function的时候, 从scope chain中,删除这个object。
如果没有嵌套的函数, 则此object再无引用, 所以它会被 当作垃圾收集
如果有嵌套的函数, 则每一个嵌套函数都引用scope chain, 而scope chain引用此object,
** 如果这些嵌套函数,只限于在其外层函数里面使用, 则 这些嵌套函数及此object仍然可以被正常地垃圾收集。
** 如果这些嵌套函数 被用于外层函数之外的更多地方, 则这些嵌套函数及此object不能正常地垃圾收集, 从而可能导致造成内存泄露,
Javascript的闭包及其使用技巧实例的更多相关文章
- 深入理解JavaScript的闭包特性如何给循环中的对象添加事件
初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...
- 如何给循环中的对象添加事件--深入理解JavaScript的闭包特性
初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...
- 深入理解JavaScript的闭包特性 如何给循环中的对象添加事件(转载)
原文参考:http://blog.csdn.net/gaoshanwudi/article/details/7355794 初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数 ...
- javascript中闭包最简单的简绍
javascript中闭包是什么 JavaScript 变量可以是局部变量或全局变量.私有变量可以用到闭包.闭包就是将函数内部和函数外部连接起来的一座桥梁. 函数的闭包使用场景:比如我们想要一个函数来 ...
- 理解javascript的闭包,原型,和匿名函数及IIFE
理解javascript的闭包,原型,和匿名函数(自己总结) 一 .>关于闭包 理解闭包 需要的知识1.变量的作用域 例1: var n =99; //建立函数外的全局变量 function r ...
- JavaScript的闭包特性如何给循环中的对象添加事件(一)
初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...
- JavaScript深入浅出-闭包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 function (){ var localVal ...
- 更快学习 JavaScript 的 6 个思维技巧
更快学习 JavaScript 的 6 个思维技巧 我们在学习JavaScript,或其他任何编码技能的时候,往往是因为这些拦路虎而裹足不前: 有些概念可能会造成混淆,尤其当你是从其他语言转过来的时候 ...
- JavaScript作用域闭包简述
JavaScript作用域闭包简述 作用域 技术一般水平有限,有什么错的地方,望大家指正. 作用域就是变量起作用的范围.作用域包括全局作用域,函数作用域以块级作用域,ES6中的let和const可以形 ...
随机推荐
- Shell 一键安装命令
现在是懒人的天下,为了迎合用户的需求,很多开源软件或者包提供的安装步骤都非常简单,大家应该看到不少类似一键安装的命令.下面是几个典型的例子: # homebrew 安装 $ ruby -e " ...
- 关于TP5的一对一、一对多同时存在的关联查询
主表SQL(tp_member) CREATE TABLE `tp_member` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id', `us ...
- Spring Boot中对自然语言处理工具包hanlp的调用详解
概 述 HanLP 是基于 Java开发的 NLP工具包,由一系列模型与算法组成,目标是普及自然语言处理在生产环境中的应用.而且 HanLP具备功能完善.性能高效.架构清晰.语料时新.可自定义的特点, ...
- Linux patch命令详解
Linux patch命令 Linux patch命令用于修补文件. patch指令让用户利用设置修补文件的方式,修改,更新原始文件.倘若一次仅修改一个文件,可直接在指令列中下达指令依序执行.如果配合 ...
- 解决web项目存在多个log4j.properties配置文件,导致日志级别配置不生效问题
java开启log4j的debug模式 -Dlog4j.debug=true tomcat启动debug模式: linux打开catalina.sh导入: export JAVA_OPTS=" ...
- OpenSSL 1.0.0生成p12、jks、crt等格式证书的命令个过程 -参考自http://lavasoft.blog.51cto.com/62575/1104993/
OpenSSL 1.0.0生成p12.jks.crt等格式证书的命令个过程 此生成的证书可用于浏览器.java.tomcat.c++等.在此备忘! 1.创建根证私钥命令:openssl g ...
- zabbix moniter
zabbix moniter http://blog.csdn.net/xiegh2014/article/category/6945291/2
- java集合之List源码解析
List是java重要的数据结构之一,我们经常接触到的有ArrayList.Vector和LinkedList三种,他们都继承来自java.util.Collection接口,类图如下 接下来,我们对 ...
- Micro QR 和QR码
QRcode.com 什么是QR码 QR码的种类 如何导入 QR码的成功之路 常见问题解答 咨询 Language Micro QR码 返回 QR码的种类 首页 二维码上只有一个定位图案,这就是M ...
- vagrant 安装笔记
本文档的编写参考慕课网视频教程,感谢慕课网提供的免费教程 http://www.imooc.com/learn/805 搭建一个环境,不需要重复配置,直接利用vagrant复制就可以了 https:/ ...