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的闭包及其使用技巧实例的更多相关文章

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

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

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

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

  3. 深入理解JavaScript的闭包特性 如何给循环中的对象添加事件(转载)

    原文参考:http://blog.csdn.net/gaoshanwudi/article/details/7355794 初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数 ...

  4. javascript中闭包最简单的简绍

    javascript中闭包是什么 JavaScript 变量可以是局部变量或全局变量.私有变量可以用到闭包.闭包就是将函数内部和函数外部连接起来的一座桥梁. 函数的闭包使用场景:比如我们想要一个函数来 ...

  5. 理解javascript的闭包,原型,和匿名函数及IIFE

    理解javascript的闭包,原型,和匿名函数(自己总结) 一 .>关于闭包 理解闭包 需要的知识1.变量的作用域 例1: var n =99; //建立函数外的全局变量 function r ...

  6. JavaScript的闭包特性如何给循环中的对象添加事件(一)

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

  7. 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 ...

  8. 更快学习 JavaScript 的 6 个思维技巧

    更快学习 JavaScript 的 6 个思维技巧 我们在学习JavaScript,或其他任何编码技能的时候,往往是因为这些拦路虎而裹足不前: 有些概念可能会造成混淆,尤其当你是从其他语言转过来的时候 ...

  9. JavaScript作用域闭包简述

    JavaScript作用域闭包简述 作用域 技术一般水平有限,有什么错的地方,望大家指正. 作用域就是变量起作用的范围.作用域包括全局作用域,函数作用域以块级作用域,ES6中的let和const可以形 ...

随机推荐

  1. 重写( override)and 重载(overload)

    重写override:是子类对父类的允许访问的方法的实现过程的重新编写,名字,返回值和形参都不能改变,即外壳不变,内心更改 重载overload:同一个类里面的方法,名字相同而参数不同,返回值可以相同 ...

  2. ts项目报错:Import sources within a group must be alphabetized

    报错:Import sources within a group must be alphabetized. 原因:import名称排序问题,要求按照字母从小到大排序:修改 tslint.json 中 ...

  3. react:路由登陆后才能访问的控制

    react-router 通过创建一个 需要认证的路由 来限制登陆后才能访问. 官方例子:https://reacttraining.com/react-router/web/example/auth ...

  4. 适配器模式adepter

    1. 主要优点 无论是对象适配器模式还是类适配器模式都具有如下优点: (1) 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构.(适配者得结构 (2) 增加了类的透明 ...

  5. Centos6.7 运行 eclipse出错解决办法

    今天在centos下运行eclipse c++出现来点问题.主要原因是jdk点安装以及环境变量始终不对. 尝试在/etc/profile中手动配置,也没有成功. 做了如下步骤成功解决. 1.查看jdk ...

  6. JSON C# Class Generator ---由json字符串生成C#实体类的工具

    json作为互联网上轻量便捷的数据传输格式,越来越受到重视.但在服务器端编程过程中,我们常常希望能通过智能提示来提高编码效率.JSON C# Class Generator 能将json格式所表示的J ...

  7. 使用shell脚本批处理控制大数据环境服务启动停止

    三台集群机器: master   192.168.168.200 slave1     192.168.168.201 slave2     192.168.168.202 1.start-maste ...

  8. Team Foundation Server 2010简体中文版

    文件名称:Team Foundation Server 2010简体中文版 文件大小:1.8 GBhttp://www.google.com/profiles/dedecms.com 下载地址: th ...

  9. 关于HTML元素点击的时候,背景颜色秒进,缓缓退出的方法

    废话不多说,上代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...

  10. STL基础--流

    流 介绍 // cout: 全局ostream对象,(typedef basic_ostream<char> ostream) // <<: ostream& ostr ...