`

JavaScript Garden - 闭包和引用

阅读更多

闭包和引用

闭包是 JavaScript 一个非常重要的特性,这意味着当前作用域总是能够访问外部作用域中的变量。
因为 函数 是 JavaScript 中唯一拥有自身作用域的结构,因此闭包的创建依赖于函数。

模拟私有变量

function Counter(start) {
    var count = start;
    return {
        increment: function() {
            count++;
        },

        get: function() {
            return count;
        }
    }
}

var foo = Counter(4);
foo.increment();
foo.get(); // 5

这里,Counter 函数返回两个闭包,函数 increment 和函数 get。 这两个函数都维持着
对外部作用域 Counter 的引用,因此总可以访问此作用域内定义的变量 count.

为什么不可以在外部访问私有变量

因为 JavaScript 中不可以对作用域进行引用或赋值,因此没有办法在外部访问 count 变量。
唯一的途径就是通过那两个闭包。

var foo = new Counter(4);
foo.hack = function() {
    count = 1337;
};

上面的代码不会改变定义在 Counter 作用域中的 count 变量的值,因为 foo.hack 没有
定义在那个作用域内。它将会创建或者覆盖全局变量 count

循环中的闭包

一个常见的错误出现在循环中使用闭包,假设我们需要在每次循环中调用循环序号

for(var i = 0; i < 10; i++) {
    setTimeout(function() {
        console.log(i);  
    }, 1000);
}

上面的代码不会输出数字 0 到 9,而是会输出数字 10 十次。

当 console.log 被调用的时候,匿名函数保持对外部变量 i 的引用,此时 for循环已经结束,i 的值被修改成了 10.

为了得到想要的结果,需要在每次循环中创建变量 i 的拷贝

避免引用错误

为了正确的获得循环序号,最好使用 匿名包裹器译者注其实就是我们通常说的自执行匿名函数)。

for(var i = 0; i < 10; i++) {
    (function(e) {
        setTimeout(function() {
            console.log(e);  
        }, 1000);
    })(i);
}

外部的匿名函数会立即执行,并把 i 作为它的参数,此时函数内 e 变量就拥有了 i 的一个拷贝。

当传递给 setTimeout 的匿名函数执行时,它就拥有了对 e 的引用,而这个值是不会被循环改变的。

有另一个方法完成同样的工作;那就是从匿名包装器中返回一个函数。这和上面的代码效果一样。

for(var i = 0; i < 10; i++) {
    setTimeout((function(e) {
        return function() {
            console.log(e);
        }
    })(i), 1000)
}

分享到:
评论

相关推荐

    17-闭包和装饰器(python和linux高级编程阶段 代码和截图)

    17-闭包和装饰器(python和linux高级编程阶段 代码和截图)17-闭包和装饰器(python和linux高级编程阶段 代码和截图)17-闭包和装饰器(python和linux高级编程阶段 代码和截图)17-闭包和装饰器(python和linux高级...

    前端面试相关-闭包的使用场景

    前端面试相关--闭包的使用场景

    04-闭包函数.html

    04-闭包函数

    ios-闭包传值.zip

    闭包可以捕获和存储它所在上下文中的常量和变量,这使得它们非常适合用于异步操作、回调函数或者封装一系列相关操作。本教程将深入探讨如何在iOS应用中使用闭包进行值传递。 闭包的基本语法: 闭包的语法通常由花...

    12.函数进阶-闭包装饰器.md

    12.函数进阶-闭包装饰器.md

    swift菜鸟入门视频教程-07-闭包

    3. **自动捕获**: Swift中的闭包会自动捕获其所在作用域内的变量,但需要注意的是,这些变量可能是按值或按引用捕获的,取决于它们的类型。 4. **闭包表达式**: Swift提供了一种简洁的语法来编写闭包,称为闭包...

    深入理解javascript原型和闭包

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

    L-闭包空间的rs-连通性 (2010年)

    这些工作不仅深化了我们对于L-闭包空间的理解,也为后续研究提供了新的视角和工具。未来的研究可以考虑将rs-连通性应用于更广泛的数学领域,如模糊拓扑学、格理论等,以进一步揭示其内在结构与应用价值。

    groovy(10)-闭包委托策略1

    闭包有三个重要的变量:`this`, `owner`, 和 `delegate`,它们各自扮演着不同的角色。 1. **this**: `this`关键字在闭包中通常指向闭包被定义时的最近作用域中的对象。这意味着,如果闭包是在某个类的实例方法中...

    论文研究-闭包算子空间范畴及其性质研究.pdf

    基于对闭包运算的性质研究,引入了闭包算子空间及其之间的连续映射概念,证明了闭包算子空间...证明了闭包算子空间范畴中(有限)积和(有限)余积的存在性,同时将闭包算子范畴与拓扑范畴联系,揭示了二者的同构性。

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

    JavaScript原型和闭包是这门语言中两个比较难以理解且与其他面向对象语言区别较大的概念。理解这两个概念,不仅能让我们更深层次地理解JavaScript,而且有助于我们了解编程语言的设计思路,拓宽我们的视野。 首先,...

    计算NFA中ε闭包

    ### 计算NFA中的ε闭包 #### 一、NFA与ε闭包概念介绍 **非确定有限自动机(NFA)**是一种理论计算模型,它扩展了确定...理解并掌握了NFA和ε闭包的概念及其计算方法后,可以进一步应用于更复杂的自动机转换问题中。

    论文研究-闭包算子与邻域系的广义化.pdf

    这些概念的经典定义依赖于特定的公理系统,例如闭包算子的定义通常依赖于下面的公理:(C1)对于任意子集A和B,如果A包含于B中,那么闭包A应包含于闭包B中;(C2)空集的闭包是空集;(C3)任何集合的闭包是其自身的...

    理解_JavaScript_闭包

    本文结合 ECMA 262 规范详解了闭包的内部工作机制,让 JavaScript 编程人员对闭包的理解从“嵌套的函数”深入到“标识符解析、执行环境和作用域链”等等 JavaScript 对象背后的运行机制当中,真正领会到闭包的实质。

    关于S-集与S-闭包 (1987年)

    本文探讨了拓扑空间中的S-集与S-闭包的概念,并在此基础上研究了S-闭空间的相关性质,同时给出了一些推广和改进前人定理的结果。在正式开始之前,需要了解几个基础概念: 1. S-集:S-集是一种特殊的子集,对于拓扑...

    M-闭包空间的积、和与商 (2010年)

    证明了M-闭包空间以及它们之间的连续映射所构成的范畴M-CS是-个topological construct但不是笛卡儿闭的(其中M是任-非空指标集),在此基础上给出了乘积M-闭包空间、直和M-闭包空间以及商M-闭包空间的概念,最后指出...

    swift-闭包、通知、协议、单例简单使用、界面传值

    博客地址 http://blog.csdn.net/qq_26598821/article/details/51254224 GitHub地址 ...swift语言的闭包(block)通知,协议,单例的简单使用。该demo较清晰得介绍四种方式的书写,简洁明了。

    javascript里的闭包是什么 什么是闭包.zip

    JavaScript中的闭包是一种重要的编程概念,它涉及到函数、作用域和变量持久化等多个核心知识点。闭包的本质是函数能够访问并操作其外部作用域内的变量,即使在其外部作用域已经结束之后仍然能保持对这些变量的访问。...

    M- L-闭包系统间的特殊映射及其范畴性质 (2012年)

    定义了M- L-闭包系统和M- L-闭包系统间的连续映射、开映射、闭映射,讨论了这些映射的性质.证明了范畴M- L-CS (即M- L-闭包系统及它们之间的连续映射构成的范畴)是topological construct .作为应用,给出了M- L-闭包...

Global site tag (gtag.js) - Google Analytics