闭包——JavaScript 中功能最强大的抽象概念之一

下面我们将看到的是 JavaScript 中必须提到的功能最强大的抽象概念之一:闭包。但它可能也会带来一些潜在的困惑。那它究竟是做什么的呢?

function makeAdder(a) {
    return function(b) {
        return a + b;
    }
}
var x = makeAdder(5);
var y = makeAdder(20);
x(6); // ?
y(7); // ?

  

makeAdder 这个名字本身应该能说明函数是用来做什么的:它创建了一个新的 adder 函数,这个函数自身带有一个参数,它被调用的时候这个参数会被加在外层函数传进来的参数上。

这里发生的事情和前面介绍过的内嵌函数十分相似:一个函数被定义在了另外一个函数的内部,内部函数可以访问外部函数的变量。唯一的不同是,外部函数已经返回了,那么常识告诉我们局部变量“应该”不再存在。但是它们却仍然存在——否则 adder 函数将不能工作。也就是说,这里存在 makeAdder 的局部变量的两个不同的“副本”——一个是 a 等于5,另一个是 a 等于20。那些函数的运行结果就如下所示:

x(6); // 返回 11
y(7); // 返回 27

  

下面来说说到底发生了什么。每当 JavaScript 执行一个函数时,都会创建一个作用域对象(scope object),用来保存在这个函数中创建的局部变量。它和被传入函数的变量一起被初始化。这与那些保存的所有全局变量和函数的全局对象(global object)类似,但仍有一些很重要的区别,第一,每次函数被执行的时候,就会创建一个新的,特定的作用域对象;第二,与全局对象(在浏览器里面是当做 window 对象来访问的)不同的是,你不能从 JavaScript 代码中直接访问作用域对象,也没有可以遍历当前的作用域对象里面属性的方法。

所以当调用 makeAdder 时,解释器创建了一个作用域对象,它带有一个属性:a,这个属性被当作参数传入 makeAdder 函数。然后 makeAdder 返回一个新创建的函数。通常 JavaScript 的垃圾回收器会在这时回收 makeAdder 创建的作用域对象,但是返回的函数却保留一个指向那个作用域对象的引用。结果是这个作用域对象不会被垃圾回收器回收,直到指向 makeAdder 返回的那个函数对象的引用计数为零。

作用域对象组成了一个名为作用域链(scope chain)的链。它类似于原型(prototype)链一样,被 JavaScript 的对象系统使用。

一个闭包就是一个函数和被创建的函数中的作用域对象的组合。

闭包允许你保存状态——所以它们通常可以代替对象来使用。这里有一些关于闭包的详细介绍。

原文地址:https://www.cnblogs.com/idzswi/p/9685940.html

时间: 2024-08-02 14:35:03

闭包——JavaScript 中功能最强大的抽象概念之一的相关文章

JavaScript中原型对象的基本概念

在之前我们学习对象的时候,讲到了创建对象的方式,一个是通过构造函数创建一个新的对象,一个是对象字面量的方式创建对象. 讲到对象就必须要认识原型对象的概念了. 1 原型对象的概念 构造函数有一个默认的属性prototype属性,这个属性指向了一个对象,这个对象就是这个构造函数的原型对象了. 同时这个原型对象种有一个constructor属性,这个属性指向的是构造函数本身. 2 原型对象中的功能 原型对象中的属性和方法,可以被实例对象所共享(不同实例对象调用的原型函数中的属性和方法为同一个). 3

JavaScript中作用域链和闭包

一.匿名函数 1.1 匿名函数的概念 ? 声明一个没有函数名的函数,就是匿名函数. ? 有函数名的函数就是具名函数. 看下面的代码: <script type="text/javascript"> /* //这里定义了一个函数,而且没有函数名.这样写语法是错误的,如果允许这样定义,那么根本就没有办法调用. //所以,我们可以用一个变量来存储一下 function(){ } */ // 声明了一个匿名函数,并把匿名函数赋值给变量f. 注意这个时候这个匿名函数并没有执行. va

JavaScript中的闭包与匿名函数

知识内容: 1.预备知识 - 函数表达式 2.匿名函数 3.闭包 一.函数表达式 1.定义函数的两种方式 函数声明: 1 function func(arg0, arg1, arg2){ 2 // 函数体 3 } 函数表达式: 1 var func = function (arg0, arg1, arg2){ 2 // 函数体 3 } 2.注意事项 函数表达式使用前必须赋值!像下面的代码是错误的: 1 say() 2 var say = function(){ 3 console.log("12

JavaScript中常见的十五种设计模式

在程序设计中有很多实用的设计模式,而其中大部分语言的实现都是基于“类”. 在JavaScript中并没有类这种概念,JS中的函数属于一等对象,在JS中定义一个对象非常简单(var obj = {}),而基于JS中闭包与弱类型等特性,在实现一些设计模式的方式上与众不同. 本文基于<JavaScript设计模式与开发实践>一书,用一些例子总结一下JS常见的设计模式与实现方法.文章略长,自备瓜子板凳~ 设计原则 单一职责原则(SRP) 一个对象或方法只做一件事情.如果一个方法承担了过多的职责,那么在

【转】深入浅出 JavaScript 中的 this

Java 等面向对象的语言中,this 关键字的含义是明确且具体的,即指代当前对象.一般在编译期确定下来,或称为编译期绑定.而在 JavaScript 中,this 是动态绑定,或称为运行期绑定的,这就导致 JavaScript 中的 this 关键字有能力具备多重含义,带来灵活性的同时,也为初学者带来不少困惑.本文仅就这一问题展开讨论,阅罢本文,读者若能正确回答 JavaScript 中的 What ’s this 问题,作为作者,我就会觉得花费这么多功夫,撰写这样一篇文章是值得的. Java

深入浅出 JavaScript 中的 this

本文来自:http://www.ibm.com/developerworks/cn/web/1207_wangqf_jsthis/ JavaScript 语言中的 this 由于其运行期绑定的特性,JavaScript 中的 this 含义要丰富得多,它可以是全局对象.当前对象或者任意对象,这完全取决于函数的调用方式.JavaScript 中函数的调用有以下几种方式:作为对象方法调用,作为函数调用,作为构造函数调用,和使用 apply 或 call 调用.下面我们将按照调用方式的不同,分别讨论

javascript中的立即执行函数(function(){…})()

javascript中的立即执行函数(function(){…})() 深入理解javascript中的立即执行函数,立即执行函数也叫立即调用函数,通常它的写法是用(function(){…})()包住业务代码,使用jquery时比较常见. ( function(){…} )()和( function (){…} () )是两种javascript立即执行函数的常见写法,最初我以为是一个括号包裹匿名函数,再在后面加个括号调用函数,最后达到函数定义后立即执行的目的,后来发现加括号的原因并非如此.要

利用argument对象在javaScript中实现重载(overload)

一些概念: 重载(overload): 什么是: 相同函数名,不同参数列表的多个函数,在调用时,可根据传入参数的不同,自动选择对应的函数调用! 为什么: 减轻调用者的负担,一个函数名,可执行多种操作 何时: 一项任务,根据不同的参数,执行不同的操作流程时 如何: js语法不支持重载效果 变通: 所有函数对象内,都自动内建了一个 其功能实现情况如下: function pay(){ console.log("微信支付") ; } function pay(num){ console.lo

JavaScript中面向对象那点事

鉴于自己在JavaScript这方面比较薄弱,所以就找了一本书恶补了一下(被称为犀利书的JavaScript权威指南).书的内容虽然多了点,但这也充分说明了js中的东西还是挺多的.虽然我们的定位不是前端,但最好还是了解一下js这个发展了将近20年但依然很火的技术. 两年前,写过一篇关于JavaScript闭包的博客,所以对闭包这个词印象很深,在看这书的时候,又看到了闭包,那么这次再看闭包,会有什么不同的理解呢? 大家都知道,在JavaScript中是没有类的概念的,更没有私有.公有的成员变量这样