您的当前位置:首页javascript闭包(Closure)用法实例简析_javascript技巧
广告

javascript闭包(Closure)用法实例简析_javascript技巧

2023-12-06 来源:菲特宠物网

本文实例讲述了javascript闭包(Closure)用法。分享给大家供大家参考,具体如下:

closure被翻译成“闭包”,感觉这东西被包装的太学术化。下面参考书本和网上资源简单探讨一下(理解不当之处务请留意)。

1、什么是闭包

官方的回答:所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。

看了上面的定义,如果你不是高手,我坚信你会和我一样愤怒的质问:这tmd是人话吗?要理解闭包,还是代码最有说服力啊,上代码:

上面代码中,注释已经写的清清楚楚。现在我们可以这么理解“闭包”:在函数体内定义另外的函数作为目标对象的方法函数(示例中就是在函数funcTest内定义另外的函数innerFuncTest作为funcTest的方法函数),而这个对象的方法函数反过来引用外层函数体中的临时变量(闭包是一种间接保持变量值的机制。示例中就是内部函数innerFuncTest引用外层函数funcTest的临时变量tmpNum,这里必须注意,临时变量可以包括外部函数中声明的所有局部变量、参数和声明的其他内部函数)。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包(示例中,调用函数的时候,myFuncTest实际调用的是innerFuncTest函数,也就是说funcTest的一个内部函数innerFuncTest在funcTest之外被调用,这时就创建了一个闭包)。

2、两个利用闭包的例子

下面举两个例子,一个是因为闭包导致了问题,而另一个则利用闭包巧妙地通过函数的作用域绑定参数。

这两个例子相关的HTML标记片断如下:

利用闭包的例子(1秒后会看到提示)由于闭包导致问题的例子1由于闭包导致问题的例子2由于闭包导致问题的例子3

(1)、因闭包而导致问题

上面的HTML标记片断中有4个元素,现在要给后三个指定事件处理程序,使它们在用户单击时报告自己在页面中的顺序,比如:当用户单击第2个链接时,报告“您单击的是第1个链接”。为此,如果编写下列为后三个链接添加事件处理程序的函数:

然后,在页面载入完成后(不然可能会报错)调用该函数:

看一下运行结果,此时单击后3个链接,会看到警告框中显示什么信息呢?——全都是“您单击的是第4个链接”。是不是令你感到十分意外?为什么?

分析:因为在badClosureExample()函数中指定给element.onclick的事件处理程序,也就是onclick那个匿名函数是在badClosureExample()函数运行完成后(用户单击链接时)才被调用的。而调用时,需要对变量i求值,解析程序首先会在事件处理程序内部查找,但i没有定义。然后,又到 badClosureExample()函数中查找,此时有定义,但i的值是4(只有i大于4才会停止执行for循环)。因此,就会取得该值——这正是闭包(匿名函数)要使用其外部函(badClosureExample)作用域中变量的结果。而且,这也是由于匿名函数本身无法传递参数(故而无法维护自己的作用域)造成的。

那么这个例子的问题怎么解决呢?其实方法有很多(自己不妨写一下看看),我认为比较简单直接的代码:

(2)、巧妙利用闭包绑定参数

还是上面的HTML片段,我们要在用户单击第一个链接时延时弹出一个警告框,怎么实现?答案是使用setTimeout()函数,这个函数会在指定的毫秒数之后调用一个函数,如: 代码如下:setTimeout(someFunc,1000);但问题是,无法给其中的someFunc函数传递参数。而使用闭包则可以轻松解决这个问题:

函数goodClosureExample用来返回一个匿名函数(闭包)。而我们可以通过为它传递参数来使返回的匿名函数绑定该参数,如: 代码如下:var good = goodClosureExample('这个参数是通过闭包绑定的');而此时,就可以将绑定了参数的good函数传递给setTimeout()实现延时警告了: 代码如下:setTimeout(good,1000) //此时good中已经绑定了参数最后,测试通过的完整代码:

3、javascript的垃圾回收原理

(1)、在javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收;

(2)、如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。

在js中使用闭包,往往会给javascript的垃圾回收器制造难题。尤其是遇到对象间复杂的循环引用时,垃圾回收的判断逻辑非常复杂,搞不好就有内存泄漏的危险,所以,慎用闭包。ms貌似已经不建议使用闭包了。

希望本文所述对大家JavaScript程序设计有所帮助。

小编还为您整理了以下内容,可能对您也有帮助:

如何理解js中的闭包

闭包(closure)是javascript的一大难点,也是它的特色。很多高级应用都要依靠闭包来实现。本次的这篇文章主要是和大家分享了如何理解js中的闭包 ,有需要的小伙伴可以看一下

1、变量作用域

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

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

javascript语言的特别之处就在于:函数内部可以直接读取全局变量,但是在函数外部无法读取函数内部的局部变量。

注意点:在函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明的是一个全局变量!

2、如何从外部读取函数内部的局部变量?

出于种种原因,我们有时候需要获取到函数内部的局部变量。但是,上面已经说过了,正常情况下,这是办不到的!只有通过变通的方法才能实现。

那就是在函数内部,再定义一个函数。

function f1(){

var n=999;

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

}在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。

这就是Javascript语言特有的"链式作用域"结构(chain scope),

子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

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

3、闭包的概念

上面代码中的f2函数,就是闭包。

各种专业文献的闭包定义都非常抽象,我的理解是: 闭包就是能够读取其他函数内部变量的函数。

由于在javascript中,只有函数内部的子函数才能读取局部变量,所以说,闭包可以简单理解成“定义在一个函数内部的函数“。

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

4、闭包的用途

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

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

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

5、使用闭包的注意点

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

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

相关推荐:

javascript闭包是什么

JavaScript闭包就是一个内部函数能够访问它所在外部函数作用域中的所有局部变量,参数或者是其他内部函数。使用闭包需要注意闭包使用增大了内存消耗,可能会造成内存泄漏

JavaScript中的闭包函数是javascript的一个重要知识点同样也是一个难点。简单的说闭包就是一个函数能够访问其函数外部作用域的变量。接下来在文章中将为大家具体介绍什么是JavaScript闭包,具有一定的参考作用,希望对大家有所帮助。

【推荐课程:JavaScript教程】

JavaScript闭包

在JavaScript中允许函数定义和函数表达式位于另一个函数的函数体中(内部函数),而且内部函数可以访问它们所在外部函数声明中的所有局部变量,参数以及其他内部函数。当其中一个内部函数被外部函数以外调用时就会形成闭包

闭包的特点

闭包函数具有以下三个方面的特点

(1)函数嵌套函数

(2)内部的函数可以访问外部函数的变量

(3)参数和变量都不会被回收

例:

<script>

function f1(){

var n=999;

nAdd=function(){

n+=1

}

function f2(){

document.write(n);

}

return f2;

}

var result=f1();

result();

nAdd();

result();

</script>输出结果为:

上述代码可以这样理解:

f1是f2的父函数,而f2被赋给了一个全局变量(return的值),这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收,这便形成了闭包。

闭包的优缺点

优点

(1)它可以保护函数内的变量安全 ,实现封装,防止变量流入其他环境发生命名冲突

(2)匿名自执行函数可以减少内存消耗

(3)在内存中维持一个变量,可以做缓存

缺点

(1)被引用的私有变量不能被销毁,增大了内存消耗,造成内存泄漏

(2)由于闭包涉及跨域访问,所以会导致性能损失,影响代码执行速度

相关文章推荐:JavaScript中闭包的含义是什么以及如何使用它

总结:

JavaScript 里的闭包是什么?应用场景有哪些

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

下面就是我的学习笔记,对于Javascript初学者应该是很有用的。

一、变量的作用域

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

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

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

var n=999;

function f1(){

alert(n);

}

f1(); // 999

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

function f1(){

var n=999;

}

alert(n); // error

这里有一个地方需要注意,函数内部声明变量的时候,一定要使用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(){n+=1}

function f2(){

alert(n);

}

return f2;

}

var result=f1();

result(); // 999

nAdd();

result(); // 1000

在这段代码中,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相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

五、使用闭包的注意点

1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。

解决方法是,在退出函数之前,将不使用的局部变量全部删除。

2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),

把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

六、思考题

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

代码片段一。

var name = "The Window";

var object = {

name : "My Object",

getNameFunc : function(){//alert(this.name);//My Object

return function(){

return this.name;// 空

};

}

};

alert(this.name);// The Window

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()()); // My Object

什么是闭包(closure),为什么要用它?

闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域,将函数内部的变量和方法传递到外部。

闭包的特性: 1.函数内再嵌套函数

2.内部函数可以引用外层的参数和变量

3.参数和变量不会被垃圾回收机制回收(by三人行慕课)

什么是闭包(closure),为什么要用它?

闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域,将函数内部的变量和方法传递到外部。

闭包的特性: 1.函数内再嵌套函数

2.内部函数可以引用外层的参数和变量

3.参数和变量不会被垃圾回收机制回收(by三人行慕课)

Js闭包的原理(图解)

什么是闭包(Closure)?
网上流传各种说法,在Javascript语言中,我的理解是: 保存着其他函数内部变量的函数,就是闭包。
挺绕的,但不虚,让我们一步步揭开它的神秘面纱!

要理解闭包,我们得先搞清楚以下几个概念:

JS的作用域分两种:全局作用域、局部作用域(也可称为函数作用域)

总的来说,Js作用域的一般机制就是:内部可访问外部的变量,外部无法访问内部的变量。

那么这套作用域机制是如何实现的呢?答案是:通过作用域链

在Js中,每当一个函数被执行,都会产生三个对象:

我们通过实例配图讲解,例如有如下 js 文件:

当浏览器运行解析 example.js 后,首先创建了全局执行环境 (Window 对象)、Window 作用域链和 Global 全局活动对象,如图:

搞明白了作用域链,离弄清楚什么是闭包就仅一步之遥了! 我们来看看下面这个实例:

当执行 var func = outer() 时,情况如图:

接下来,当执行 console.log(func()) 时, 情况如图:

Js闭包的原理(图解)

什么是闭包(Closure)?
网上流传各种说法,在Javascript语言中,我的理解是: 保存着其他函数内部变量的函数,就是闭包。
挺绕的,但不虚,让我们一步步揭开它的神秘面纱!

要理解闭包,我们得先搞清楚以下几个概念:

JS的作用域分两种:全局作用域、局部作用域(也可称为函数作用域)

总的来说,Js作用域的一般机制就是:内部可访问外部的变量,外部无法访问内部的变量。

那么这套作用域机制是如何实现的呢?答案是:通过作用域链

在Js中,每当一个函数被执行,都会产生三个对象:

我们通过实例配图讲解,例如有如下 js 文件:

当浏览器运行解析 example.js 后,首先创建了全局执行环境 (Window 对象)、Window 作用域链和 Global 全局活动对象,如图:

搞明白了作用域链,离弄清楚什么是闭包就仅一步之遥了! 我们来看看下面这个实例:

当执行 var func = outer() 时,情况如图:

接下来,当执行 console.log(func()) 时, 情况如图:

谁来解释一下Javascript闭包的概念

闭包是可以包含自由(未绑定到特定对象)变量的代码块;这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)。"闭包" 一词来源于以下两者的结合:要执行的代码块(由于自由变量被包含在代码块中,这些自由变量以及它们引用的对象没有被释放)和为自由变量提供绑定的计算环境(作用域)。

简而言之,闭包的作用就是在函数执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回函数所占用的资源,因为函数的内部函数的执行需要依赖函数中的变量。

一个闭包的实例:

function Counter(start){

    var count = start;

    return{

        increment:function(){

            count++;

        },

        get:function(){

            return count;

        }

    }

}

var foo = Counter(4);

foo.increment();

foo.get();// 5

JavaScript中闭包的含义是什么以及如何使用它

本文章将分享有关JavaScript中闭包的知识点,有一定的参考价值,希望对大家有所帮助

闭包是函数和声明该函数的词法环境的组合,当内部函数被保存到外部时,将会生成闭包而闭包会导致原有作用域链不释放,造成内存泄露,但同时闭包也是非常有用的,因为它可以将某些数据与对该数据的操作进行关联。

例:

function demo() {

var name = '张三'; // name 是demo()创建的局部变量

function demo1() { //demo1()是demo()中的内部函数(闭包)

console.log(name); // 使用父函数中声明的变量

}

demo1();

}demo();运行结果

函数demo()中创建一个名为name的局部变量和一个名为demo1()的内部函数。 demo1()函数只能在demo()函数体内使用。 demo1没有自己的局部变量。但是由于内部函数可以访问外部函数的变量,所以demo1()可以访问父函数demo()中声明的变量名name。但是如果有同名变量 name 在demo1中被定义,则会使用 自己函数中定义的 name。该例子说明嵌套函数可以访问在其外部作用域中声明的变量。

如果上面的代码改成这样结果会如何?

function demo() {

var name = '张三';

function demo1() {

console.log(name);

}

return demo1;

}

var newDemo = demo();

newDemo();运行结果

由运行结果可知两段代码结果一样,内部函数demo1()在执行之前被外部函数返回形成闭包,在这种情况下,newDemo()是运行demo时所创建的函数demo1的一个引用,所以当调用newDemo()时,变量名name仍可以传递给console.log(name)。

示例

function num(x) {

return function(y) {

return x + y;

};}

var num1= num(2);

var num2 = num(3);

console.log(num1(2));// 4

console.log(num2(2));// 5运行结果

定义一个函数num(x)用于接收一个参数x并返回一个新函数,这个新函数还接收一个参数y并返回x和y之和;同时又定义了两个新的值num1,num2都为闭包且传值分别为2,3.

总结:

菲特宠物网还为您提供以下相关内容希望对您有帮助:

JavaScript中闭包的含义是什么以及如何使用它

例:function demo() { var name = '张三'; // name 是demo()创建的局部变量 function demo1() { //demo1()是demo()中的内部函数(闭包) console.log(name); // 使用父函数中声明的变量 } demo1(); }...

如何理解js中的闭包

javascript语言的特别之处就在于:函数内部可以直接读取全局变量,但是在函数外部无法读取函数内部的局部变量。注意点:在函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明的是一个全局变量!2、如何从外...

Js闭包的原理(图解)

当浏览器运行解析 example.js 后,首先创建了全局执行环境 (Window 对象)、Window 作用域链和 Global 全局活动对象,如图:搞明白了作用域链,离弄清楚什么是闭包就仅一步之遥了! 我们来看看下面这个实例:当执行 var ...

什么是Javascript的闭包

function displayName() { console.log(name); } //当 displayName 函数返回后,这个函数还能访问 init 函数里面定义的变量。 return displayName;}var closure = init();closure();ZilongshanrenundefineddisplayName 是一...

javascript闭包是什么

JavaScript闭包就是一个内部函数能够访问它所在外部函数作用域中的所有局部变量,参数或者是其他内部函数。使用闭包需要注意闭包使用增大了内存消耗,可能会造成内存泄漏JavaScript中的闭包函数是javascript的一个重要知识点同样也是一...

谁来解释一下Javascript闭包的概念

简而言之,闭包的作用就是在函数执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回函数所占用的资源,因为函数的内部函数的执行需要依赖函数中的变量。一个闭包的实例:function Counter(start){ var count = st...

javascript的闭包是什么意思?有什么用?

\x0d\x0a简而言之,闭包的作用就是在a执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量。这是对闭包作用的非常直白的描述,不专业也不严谨,...

js闭包的理解是什么

通过使用闭包,可以避免全局变量的污染,实现数据的封装和保护,提高程序的安全性和可维护性。在实际开发中,我们可以使用闭包来模拟面向对象编程的一些特性,比如私有属性和方法的实现。当然,闭包也有着一些缺点和需要注意的地方...

JS中for循环闭包问题如何解决

然而javascript 有些常见的闭包问题,比如上面的例子,那么我们来看看怎么解决这些问题。解决方案一:加一层闭包,i 以函数参数形式传递给内层函数:结果就是点击相应的li会弹出相应的数字,比如点第三个li,会出现以下效果:...

JavaScript 里的闭包是什么?应用场景有哪些

三、闭包的概念 上一节代码中的f2函数,就是闭包。各种专业文献上的"闭包"(closure)定义非常抽象,很难看懂。我的理解是,闭包就是能够读取其他函数内部变量的函数。由于在Javascript语言中,只有函数内部的子函数才能读取...

Top