`
473687880
  • 浏览: 535761 次
文章分类
社区版块
存档分类
最新评论

深入理解JavaScript闭包

 
阅读更多
深入理解,Javascript,js,闭包,深入理解Javascript,js闭包
<style type="text/css"> <!-- p {text-indent:2em} --> </style>

简言之,理解JavaScript闭包(Closure)很多问题的关键是闭包是不进行编译的,只有在调用的时候才进行解析。


维基百科上对闭包的定义是:Closure(alsolexical closureorfunction closure) is afunctiontogether with areferencing environmentfor thenon-local variablesof that function.用我拙略的语言翻译过来就是闭包(又称“词法闭包”或“函数闭包”)是一个包含了非本地变量引用环境的函数。

闭包其实就是一个函数;如果一个函数访问了它的外部变量,那么它就是一个闭包。一个典型的例子就是全局变量的使用。所以从技术上来讲,在Javascript中,每个function都是闭包,因为它总是能访问在它外部定义的变量。


示例:

首先来看一个简单的例子:

function say667() {
    // Local variable that ends up within closure
    var num = 666;
    var sayAlert = function() { alert(num); }
    num++;
    return sayAlert;
}
var sayAlert = say667();
sayAlert()

执行结果应该弹出667而不是666,这个应该很好理解。再来看一个容易迷惑的经典例子:

function buildList(list) {
    var result = [];
    for (var i = 0; i < list.length; i++) {
        var item = 'item' + list[i];
        result.push( function() {alert(item + ' ' + list[i])} );
    }
    return result;
}
function testList() {
    var fnlist = buildList([1,2,3]);
    // using j only to help prevent confusion - could use i
    for (var j = 0; j < fnlist.length; j++) {
        fnlist[j]();
    }
}

testList的执行结果是弹出item3undefined窗口三次。因为这三个闭包是在同一个外部函数中定义的,item的值为最后计算的结果,但是当i跳出循环时i值为3,所以list[3]的结果为undefined.


将引用变为拷贝

理解问题的关键是,Javascript是一门解释性的语言,一个函数内部定义的另一个函数(即闭包)只有在调用的时候才进行解析闭包中引用的变量的值是此时内存中的值buildList函数中定义闭包时,使用了参数"list"以及内部变量"i"引用,而不是拷贝。因此只有当闭包执行时,也就是在testList函数中调用时,才会开始引用list和i的值并输出;而此时i的值为4,结果可想而知了!

为了达到预期的效果,我们来改造一下buildList函数,而改造的关键是在每次循环中创建变量i的拷贝,也就是将引用变为拷贝​一种简单的方法就是使用自执行的“匿名函数”来对闭包进行包裹:

function buildList(list) {
    var result = [];
    for (var i = 0; i < list.length; i++) {
        (function(r){
            var item = 'item' + list[r];
            result.push( function() {alert(item + ' ' + list[r])} );
        })(i);
    }
    return result;
}

这样,在函数buildList执行的时候,匿名函数会立即执行,并把i作为参数;此时匿名函数内部的变量r相当于有了i的一个拷贝,而r的值是不会被外部的循环改变的。因此函数testList的执行结果是分别弹出“item11”、“item2 2”、“item3 3”。​


你理解了吗?

要小心的是,在Javascript函数参数传递的时候,只有基本类型的参数会被拷贝,对象类型的参数传递的是引用。因此,如果给匿名函数传递对象类型的参数时(没有人会这么做吧!),要小心出现意外的情况;举个变态的例子:

function buildList(list) {
    var result = [];
    var obj = {};
    for (obj.i = 0; obj.i < list.length; obj.i++) {
        (function(r){
            var item = 'item' + list[r.i];
            result.push( function() {alert(item + ' ' + list[r.i])} );
        })(obj);
    } 
    return result;
}

函数testList的执行结果是什么呢?是分别弹出“item1undefined”、“item2undefined”、“item3undefined”​​窗口,跟前面两种写法的结果都不一样。原因是匿名函数立即执行后,其内部变量item被正确赋值,等到testList函数运行时,闭包中引用的r.i其实就是obj对象的i变量,它的值当然是3,结果就可想而知了。

Javascript闭包,你理解了吗?​


分享到:
评论

相关推荐

    深入理解_JavaScript_闭包

    总之,深入理解JavaScript闭包对于编写高效、可维护的代码至关重要。掌握闭包不仅有助于解决实际问题,还能提高编程技巧和对JavaScript语言机制的理解。在日常开发中,无论是用于实现模块化、数据封装,还是处理异步...

    深入理解JavaScript系列

    深入理解JavaScript系列(16):闭包(Closures) 深入理解JavaScript系列(17):面向对象编程之一般理论 深入理解JavaScript系列(18):面向对象编程之ECMAScript实现 深入理解JavaScript系列(19):求值策略...

    深入理解javascript原型和闭包

    深入理解javascript原型和闭包(01)——一切都是对象 深入理解javascript原型和闭包(02)——函数和对象的关系

    深入理解javascript原型和闭包.pdf

    总的来说,深入理解原型和闭包对于掌握JavaScript至关重要,因为它们不仅体现了JavaScript独特的设计思想,还是区别于其他主流编程语言的关键特性。无论是原型链和作用域链的理解,还是函数作为一等对象的灵活使用,...

    深入理解Javascript闭包 新手版

    JavaScript闭包是编程语言中一个重要的概念,尤其对于JavaScript开发者来说,理解闭包至关重要。闭包的本质是一个函数,这个函数能够访问并操作其外部作用域的变量,即使在其外部作用域已经不再存在的情况下也能保持...

    深入理解JavaScript 闭包究竟是什么

    JavaScript 闭包是一种重要的编程概念,它涉及到函数和作用域之间的关系。闭包是指一个函数能够访问并操作其外部作用域中的变量,即使这个函数在外部作用域...理解和熟练掌握闭包对于JavaScript开发者来说至关重要。

    深入理解JavaScript的闭包技术整理.pdf

    深入理解JavaScript的闭包技术整理.pdf

    深入理解JavaScript系列(.chm)

    深入理解JavaScript系列(16):闭包(Closures) 深入理解JavaScript系列(17):面向对象编程之一般理论 深入理解JavaScript系列(18):面向对象编程之ECMAScript实现 深入理解JavaScript系列(19):求值策略...

    JavaScript闭包

    Javascript中有几个非常重要的语言特性——对象、原型继承、闭包。其中闭包 对于那些使用传统静态...本文将以例子入手来介绍Javascript闭包的语言特性,并结合一点 ECMAScript语言规范来使读者可以更深入的理解闭包。

    javascript闭包详解中文word版

    本文将以例子入手来介绍Javascript闭包的语言特性,并结合一点 ECMAscript语言规范来使读者可以更深入的理解闭包。闭包是Closure, 资源太大,传百度网盘了,链接在附件中,有需要的同学自取。

    javascript深入理解js闭包.docx

    在JavaScript中,闭包是一种特殊的函数,它能够访问并操作其定义时的作用域,即使该作用域在其执行时已经不存在。闭包的概念是基于JavaScript的词法作用...理解并掌握闭包对于编写高效、安全的JavaScript代码至关重要。

    深入解析Javascript闭包的功能及实现方法

    JavaScript中的闭包是一种强大的...理解并熟练运用闭包是JavaScript开发中的重要技能,它能够帮助开发者编写更加灵活和高效的应用代码。在实际开发中,应根据需求选择合适的闭包实现方式,并注意避免不必要的内存占用。

    JavaScript闭包深入理解.pdf

    深入理解闭包,还需要了解JavaScript的作用域、作用域链、执行上下文等概念。作用域决定了变量的可见性,全局作用域在整个脚本中都可访问,而函数作用域仅在函数内部可见。当函数执行时,会创建一个执行上下文,其中...

    [深入理解JS闭包]帮助你快速学习js的闭包,简单高效的文档资源

    JavaScript 闭包是一种强大的特性,它允许函数访问和操作其外部作用域的变量,即使在其外部函数执行完毕后,闭包依然能...通过深入理解闭包,开发者可以更好地利用 JavaScript 的特性,写出更高效、更易于维护的代码。

    深入理解javascript原型和闭包1

    JavaScript是一种动态类型的...通过这些深入的讲解,你应该能更好地理解JavaScript中对象、原型、函数和闭包的工作原理,为你的JavaScript开发打下坚实的基础。在实际编程中,灵活运用这些知识可以解决许多复杂的问题。

    理解 JavaScript 闭包

    为了深入理解闭包,我们不仅需要知道它是如何构成的,还需要理解它背后的运行机制。 首先,要明确什么是闭包。闭包是由函数以及创建该函数的词法环境组合而成。在JavaScript中,闭包使一个内部函数可以访问其外部...

Global site tag (gtag.js) - Google Analytics