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不能正常地垃圾收集, 从而可能导致造成内存泄露,

转载于:https://www.cnblogs.com/GameEngine/p/6427232.html

Javascript的闭包及其使用技巧实例相关推荐

  1. 深入理解JavaScript的闭包特性如何给循环中的对象添加事件

    初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...

  2. Javascript实现页内查找关键词实例

    Javascript实现页内查找关键词实例 <html> <META HTTP-EQUIV="Content-Type" content="text/h ...

  3. 转载:JavaScript 的55个经典技巧

    1. οncοntextmenu="window.event.returnValue=false" 将彻底屏蔽鼠标右键 <table border οncοntextmenu ...

  4. 深入理解javascript的闭包

    闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域 ...

  5. 曼哈顿距离java实现_基于javascript实现获取最短路径算法代码实例

    这篇文章主要介绍了基于javascript实现获取最短路径算法代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 代码如下 //A算法 自动寻路 ...

  6. JavaScript中闭包实现的私有属性的getter()和setter()方法

    注意: 以下的输出都在浏览器的控制台中 <!DOCTYPE html> <html> <head><meta charset="utf-8" ...

  7. javascript 一些小常用的技巧

    1. οncοntextmenu="window.event.returnValue=false" 将彻底屏蔽鼠标右键 <table border οncοntextmenu ...

  8. JAVASCRIPT常用20种小技巧汇总

    1.TEXTAREA自适应文字行数的多少 2.脚本永不出错 <script LANGUAGE="javascript"> </script> 3.ENTER ...

  9. JavaScript:闭包

    在说JavaScript中闭包概念之前,我们先来了解一下作用域和变量生命周期的问题.作用域在前面的博客中有提到,大家可以点击查看一下,关于变量的生命周期,什么是生命周期?也就是变量从创建到销毁的一个过 ...

最新文章

  1. Linux系统备份树莓派,全平台备份树莓派的方法
  2. 分布式服务防雪崩熔断器,Hystrix理论+实战
  3. 使用gdb调试多进程和多线程
  4. Spring整合Mybatis和JUnit
  5. 如何火眼金睛鉴定那些单细胞转录组中的混杂因素
  6. 转list_quot;quot;转 Int,{} 转 List,还有什么奇葩的 JSON 要容错?| 实战
  7. Spring mvc介绍
  8. 1.vue前端项目实战-登录功能
  9. 在百度实习的100天
  10. Java 使用嵌套 for 循环打印皇冠
  11. Selenium获取浏览器Network数据包
  12. NoSQLBooster for MongoDB基本使用步骤
  13. 上海互联网整体沉沦:盛大巨人全没落 8年没出一个马云
  14. Android Rect相关方法
  15. 【其他】手机bilibili的视频文件在哪个目录
  16. mysql5.7 主从切换_mysql5.7主从切换(master/slave switchover)
  17. Python代码画喜羊羊怎么画_利用Python让你的命令行像蔡徐坤一样会打篮球
  18. 【北亚数据恢复】Hp DL380服务器raid磁盘故障导致数据库数据丢失的数据恢复案例
  19. element ui的气泡确认框 点击确定没反应的问题
  20. 在家办公用这个远程办公软件跟去公司一样

热门文章

  1. Linux系统命令常用查询
  2. RxJava 2.x 入门
  3. Java 面向对象四大特性
  4. visio 模板_盒图模板一键套用,便捷绘制精美盒图图表
  5. motan yar php,motan学习笔记 六 opentracing Brave+zipkin实现-Go语言中文社区
  6. 在Ubuntu中自动运行KMS服务
  7. mysql istransient_由于 MySQL 版本问题导入报错
  8. sql查询百分之20到百分之40的数据_拼多多面试题:如何查找前20%的数据?
  9. 对NUnitAddIn做了下修改
  10. Visio对象插入Word后周围空白过大