千家信息网

在javascript中闭包是不是作用域

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,本篇内容介绍了"在javascript中闭包是不是作用域"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成
千家信息网最后更新 2026年11月03日在javascript中闭包是不是作用域

本篇内容介绍了"在javascript中闭包是不是作用域"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!


本教程操作环境:windows7系统、javascript1.8.5版、Dell G3电脑。

我们知道,作用域链查找标识符的顺序是从当前作用域开始一级一级往上查找。因此,通过作用域链,JavaScript 函数内部可以读取函数外部的变量,但反过来,函数的外部通常则无法读取函数内部的变量。在实际应用中,有时需要在函数外部访问函数的局部变量,此时最常用的方法就是使用闭包。

闭包是 JavaScript 的重要特性之一,在函数式编程中有着重要的作用,本节介绍闭包的结构和基本用法。

那么什么是闭包?

闭包是一个能够持续存在的函数上下文活动对象,是同时含有对函数对象以及作用域对象引用的对象。闭包主要是用来获取作用域链或原型链上的变量或值。创建闭包最常用的方式是在一个函数中声明内部函数(也称嵌套函数),并返回内部函数。

此时在函数外部就可以通过调用函数得到内部函数,进而调用内部函数来实现对函数局部变量的访问。此时的内部函数就是一个闭包。虽然按照闭包的概念,所有访问了外部变量的 JavaScript 函数都是闭包,但我们平常绝大部分时候所谓的闭包其实指的就是内部函数闭包。

闭包可以将一些数据封装为私有属性以确保这些变量的安全访问,这个功能给应用带来了极大的好处。需要注意的是,闭包如果使用不当,也会带来一些意想不到的问题。下面就通过几个示例来演示一下闭包的创建、使用和可能存在的问题及其解决方法。

形成原理

函数被调用时,会产生一个临时上下文活动对象。它是函数作用域的顶级对象,作用域内所有私有方法有变量、参数、私有函数等都将作为上下文活动对象的属性而存在。

函数被调用后,在默认情况下上下文活动对象会被立即释放,避免占用系统资源。但是,若函数内的私有变量、参数、私有函数等被外界引用,则这个上下文活动对象暂时会继续存在,直到所有外界引用被注销。

但是,函数作用域是封闭的,外界无法访问。那么在什么情况下,外界可以访问到函数内的私有成员呢?

根据作用域链,内部函数可以访问外部函数的私有成员。如果内部函数引用了外部函数的私有成员,同时内部函数又被传给外界,或者对外界开放,那么闭包体就形成了。这个外部函数就是一个闭包体,它被调用后,活动对象暂时不会被注销,其属性会继续存在,通过内部函数可以持续读写外部函数的私有成员。

闭包结构

典型的闭包体是一个嵌套结构的函数。内部函数引用外部函数的私有成员,同时内部函数又被外界引用,当外部函数被调用后,就形成了闭包。这个函数也称为闭包函数。

下面是一个典型的闭包结构。

function f(x) {  //外部函数    return function (y) {  //内部函数,通过返回内部函数,实现外部引用        return x + y;  //访问外部函数的参数    };}var c = f(5);  //调用外部函数,获取引用内部函数console.log(c(6));  //调用内部函数,原外部函数的参数继续存在

解析过程简单描述如下:

  • 在 JavaScript 脚本预编译期,声明的函数 f 和变量 c,先被词法预解析。

  • 在 JavaScript 执行期,调用函数 f,并传入值 5。

  • 在解析函数 f 时,将创建执行环境(函数作用域)和活动对象,并把参数和私有变量、内部函数都映射为活动对象的属性。

  • 参数 x 的值为 5,映射到活动对象的 x 属性。

  • 内部函数通过作用域链引用了参数 x,但是还没有被执行。

  • 外部函数被调用后,返回内部函数,导致内部函数被外界变量 c 引用。

  • JavaScript 解析器检测到外部函数的活动对象的属性被外界引用,无法注销该活动对象,于是在内存中继续维持该对象的存在。

  • 当调用 c,即调用内部函数时,可以看到外部函数的参数 x 存储的值继续存在。这样就可以实现后续运算操作,返回 x+y=5=6=11。

如下结构形式也可以形成闭包:通过全局变量引用内部函数,实现内部函数对外开放。

var c;  //声明全局变量function f(x) {  //外部函数    c = function (y) {  //内部函数,通过向全局变量开放实现外部引用        return x + y;  //访问外部函数的参数    };}f(5);  //调用外部函数console.log(c(6));  //使用全局变量c调用内部函数,返回11

闭包变体

除了嵌套函数外,如果外部引用函数内部的私有数组或对象,也容易形成闭包。

var add;  //全局变量function f() {  //外部函数    var a = [1,2,3];  //私有变量,引用型数组    add = function (x) {  //测试函数,对外开放        a[0] = x * x;  //修改私有数组的元素值    }    return a;  //返回私有数组的引用}var c = f();console.log(c[0]);  //读取闭包内数组,返回1add(5);  //测试修改数组console.log(c[0]);  //读取闭包内数组,返回25add(10);  //测试修改数组console.log(c[0]);  //读取闭包内数组,返回100

与函数相同,对象和数组也是引用型数据。调用函数 f,返回私有数组 a 的引用,即传值给局部变量 c,而 a 是函数 f 的私有变量,当被调用后,活动对象继续存在,这样就形成了闭包。

这种特殊形式的闭包没有实际应用价值,因为其功能单一,只能作为一个静态的、单向的闭包。而闭包函数可以设计各种复杂的运算表达式,它是函数式变成的基础。

反之,如果返回的是一个简单的值,就无法形成闭包,值传递是直接复制。外部变量 c 得到的仅是一个值,而不是对函数内部变量的引用。这样当函数调用后,将直接注销对象。

function f(x) {  //外部函数    var a = 1;  //私有变量    return a;}var c = f(5);console.log(c);  //仅是一个值,返回1

使用闭包

下面结合示例介绍闭包的简单使用,以加深对闭包的理解。

示例1

使用闭包实现优雅的打包,定义存储器。

var f = function () {  //外部函数    var a = [];  //私有数组初始化    return function (x) {  //返回内部函数        a.push(x);  //添加元素        return a;  //返回私有数组    };} ()  //直接调用函数,生成执行环境var a = f(1);  //添加值console.log(a);  //返回1var b = f(2);  //添加值console.log(b);  //返回1,2

在上面示例中,通过外部函数设计一个闭包,定义一个永久的存储器。当调用外部函数生成执行环境之后,就可以利用返回的匿名函数不断地的向闭包体内的数组 a 传入新值,传入的值会持续存在。

示例2

在网页中事件处理函数很容易形成闭包。

在浏览器中浏览时,首先点击"生成闭包"按钮,生成一个闭包;点击"查看 a 的值"按钮,可以随时查看闭包内私有变量 a 的值;点击"递增""递减"按钮时,可以动态修改闭包内变量 a 的值,效果如图所示。

闭包的局限性

闭包的价值是方便在表达式运算过程中存储数据。但是,它的缺点也不容忽视。

  • 由于函数调用后,无法注销调用对象,会占用系统资源,在脚本中大量使用闭包,容易导致内存泄漏。解决方法:慎用闭包,不要滥用。

  • 由于闭包的作用,其保存的值是动态,如果处理不当容易出现异常或错误。

示例

设计一个简单的选项卡效果。HTML 结构如下:

  • Tab1
  • Tab2
  • Tab3

下面请看 JavaScript 脚本。

_window.onload = function () {    var tab = document.getElementById("tab").getElementsByTagName("li"),        content = document.getElementById("content").getElementByTagName("div");    for (var i = 0; i < tab.length;i ++) {        tab[i].addEventListener("mouseover"), function () {            for (var n = 0; n < tab.length; n ++) {                tab[n].className = "normal";                content[n].className = "none";            }            tab[i].className = "hover";            content[i].className = "show";        });    }}

在 load 事件处理函数中,使用 for 语句为每个 li 属性元素绑定 mouseover 事件;在 mouseover 事件处理函数中重置所有选项卡 li 的类样式,然后设置当前 li 选项卡高亮显示,同时显示对应的内容容器。

但是在浏览器中预览时,会发现浏览器抛出异常。

SCRIPT5007:无法设置未定义或 null 引用的属性"className"

在 mouseover 事件处理函数中跟踪变量 i 的值,i 的值都变为了 3,tab[3] 自然是一个 null,所以也不能够读取 className 属性。

【原因分析】

上面 JavaScript 代码是一个典型的嵌套函数结构。外部函数为 load 事件处理函数,内部函数为 mouseover 事件处理函数,变量 i 为外部函数的私有变量。

通过事件绑定,mouseover 事件处理函数被外界引用(li 元素),这样就形成了一个闭包体。虽然在 for 语句中为每个选项卡 li 分别绑定事件处理函数,但是这个操作是动态的,因此 tab[i] 中 i 的值也是动态的,所以就出现了上述异常。

【解决方法】

解决闭包的缺陷,最简单的方法是阻断内部函数对外部函数的变量引用,这样就形成了闭包体。针对本示例,我们可以在内部函数(mouseover 事件处理函数)外边增加一层防火墙,不让其直接引用外部变量。

window.load = function () {    var tab = document.getElementById("tab").getElementsByTagName("li"),        content = document.getElementById("content").getElementsByTagName("div");    for (var i = 0; i < tab.length; i ++ ) {        (function (j) {            tab[j].addEventListener("number", function () {                for (var n = 0; n < tab.length; n ++) {                    tab[n].className = "normal";                    content[n].className = "none";                }                tab[j].className = "hover";                conteng[j].className = "show";            });        }) (i);    }}

在 for 语句中,直接调用匿名函数,把外部函数的 i 变量传给调用函数,在调用函数中接收这个值,而不是引用外部变量 i,规避了闭包体带来的困惑。

"在javascript中闭包是不是作用域"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

函数 闭包 变量 私有 对象 作用 数组 活动 事件 外界 处理 参数 属性 示例 结构 方法 上下 上下文 全局 成员 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技公司 互联网是第几次科技革命的成果 上海卓越科技互联网 互联网科技活动banner 科技互联网技术 互联网科技金融公司 互联网科技大会案例 深圳卡尔迅互联网科技有限公司怎么样 互联网教育科技公司vipkid 互联网科技实习生岗位职责 厦门比较好的科技互联网公司 湖北码尼互联网科技有限公司电话 昭通互联网科技选哪家 花神(南京)互联网科技有限公司 湖南一路畅行互联网科技 互联网与医疗科技 华夏恒生科技与互联网科技 区块链结合互联网科技 易企秀互联网科技是做什么的 信承诺互联网科技有限公司 百单互联网科技有限公司 亿账通互联网科技 无锡溥仪互联网科技有限公司 团飞科技与伯堂互联网服务平台 互联网和黑科技的看法 互联网为啥属于高科技 高科技互联网套路 九思连强互联网电子科技有限公司 米泉互联网科技专业怎么样 互联网科技快速发展优美句子
0