js闭包处理

news/2025/2/13 23:26:37/

闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。

闭包的作用:通过一系方法,将函数内部的变量(局部变量)转化为全局变量

一、变量的作用域

要理解闭包,首先必须理解Javascript特殊的变量作用域。

变量的作用域无非就是两种:全局变量局部变量

Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。

var n=999;

function f1(){
alert(n);                                                                //全局变量
}

f1();    // 999

另一方面,在函数外部无法读取函数内的局部变量。

function f1(){
var n=999;                                                               //局部变量
}

alert(n);   // n is not defined [n没有被定义]

这里有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!

function f1(){
n=999;

}

f1();

alert(n);   // 999

二、如何从外部读取局部变量?

出于种种原因,我们有时候需要得到函数内的局部变量。但是,前面已经说过了,正常情况下,这是办不到的,只有通过变通方法才能实现。那就是在函数的内部,再定义一个函数。

function f1(){

var n=999;   

function f2(){
alert(n);    // 999
}

}

在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。这就是Javascript语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立

既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!

function f1(){

var n=999;

function f2(){
alert(n); 
}

return  f2;

}

var result=f1();

result(); // 999

三、闭包的概念

上一节代码中的f2函数,就是闭包

各种专业文献上的"闭包"(closure)定义非常抽象,很难看懂。我的理解是,闭包就是能够读取其他函数内部变量的函数

由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。

所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

四、闭包的用途

闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

function f1(){

var n=999;

nAdd=function(){

alert(n+=1);  

}

function f2(){
alert(n);
}

return f2;

}

var result=f1();

result(); //999

nAdd();//1000

result(); //1001

在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。

为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

这段代码中另一个值得注意的地方,就是"nAdd=function(){n+=1}"这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个操控者,可以在函数外部对函数内部的局部变量进行操作。

五、使用闭包的注意点

1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

六、思考题

如果你能理解下面两段代码的运行结果,应该就算理解闭包的运行机制了。

代码片段一。

    var name = "The Window";

var object = {
name : "My Object",

getNameFunc : function(){   //递归
return function(){
return this.name;
};

}

};

alert(object.getNameFunc()());


代码片段二。

var name = "The Window";

var object = {
name : "My Object",

getNameFunc : function(){
var that = this;
return function(){
return that.name;
};

}

};

alert(object.getNameFunc()());


http://www.ppmy.cn/news/41458.html

相关文章

不良事件上报系统源码 有演示,已在多家医院运营多年

不良事件上报系统源码,医院安全不良事件管理系统源码 技术架构:前后端分离,仓储模式,BS架构,有演示,已在多家医院完美运营。 相关技术:PHPvscodevue2elementlaravel8mysql5.7 文末获取联系&am…

1.让自己习惯C++(条款1-4)

目录 条款01:视C为一个语言联邦 条款02:尽量以const,enum,inline替换#define 条款03:尽可能使用 const 条款04:确定对象被使用前已经被初始化 条款01:视C为一个语言联邦 可以将C的语言分为…

黑马点评Redis实战(短信登录;商户查询缓存)

黑马点评 通过一个类似于大众点评的项目了解学习redis在实战项目中的使用,下面是项目中会涉及到的模块: 一、导入黑马点评项目 导入springboot项目,导入sql脚本到数据库,开启nginx,更改项目配置文件中的redis和mys…

腾讯空降测试工程师,绩效次次拿S,真是砂纸擦屁股,给我露了一手啊

​上周我们公司的绩效面谈全部结束了,每年到这个时间点就是打绩效的时候了,对于职场打工人来说绩效绝对是最重要的事情之一,原因也很简单:奖金、晋升、涨薪都和它有关系。 比如下面这个美团员工在脉脉上的自曝就很凄凉&#xff1…

leetcode785. 判断二分图

https://leetcode.cn/problems/is-graph-bipartite/判断给定的图是否为二分图,如果图是二分图,返回 true ,否则,返回 false 。二分图 定义:如果能将一个图的节点集合分割成两个独立的子集 A 和 B ,并使图中…

科易动力携手企企通,打造数字化采购与供应链管理平台

近日,苏州科易新动力科技有限公司(以下简称“科易动力”)携手企企通举办了数字化采购项目启动会,双方企业高层、相关部门负责人参加了此次会议。会上,双方就数字化采购管理平台建设达成共识,企企通将将根据…

如何在Linux上安装宝塔并实现公网远程登录宝塔面板【内网穿透】

文章目录前言1. 安装宝塔2. 安装cpolar内网穿透3. 远程访问宝塔4. 固定http地址5. 配置二级子域名6. 测试访问二级子域名转发自CSDN远程穿透的文章:Linux安装宝塔,并实现公网远程登录宝塔面板【内网穿透】 前言 宝塔面板作为建站运维工具,它…

代码随想录算法训练营第四十一天-动态规划3|343. 整数拆分 ,96.不同的二叉搜索树

343整数拆分,有两种解法,一种是数学的方法,利用当f>4时,2*(f - 2)2f - 4 > f的性质,将所有的因子都拆成3,最后的余数再乘进去。另外一种是动态规划,把前面的数拆了…