最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

关于JavaScript中闭包的详解

来源:懂视网 责编:小采 时间:2020-11-27 20:23:27
文档

关于JavaScript中闭包的详解

关于JavaScript中闭包的详解:闭包是什么在 JavaScript 中,闭包是一个让人很难弄懂的概念。ECMAScript 中给闭包的定义是:闭包,指的是词法表示包括不被计算的变量的函数,也就是说,函数可以使用函数之外定义的变量。是不是看完这个定义感觉更加懵逼了?别急,我们来分析一下。闭包是一
推荐度:
导读关于JavaScript中闭包的详解:闭包是什么在 JavaScript 中,闭包是一个让人很难弄懂的概念。ECMAScript 中给闭包的定义是:闭包,指的是词法表示包括不被计算的变量的函数,也就是说,函数可以使用函数之外定义的变量。是不是看完这个定义感觉更加懵逼了?别急,我们来分析一下。闭包是一

闭包是什么

在 JavaScript 中,闭包是一个让人很难弄懂的概念。ECMAScript 中给闭包的定义是:闭包,指的是词法表示包括不被计算的变量的函数,也就是说,函数可以使用函数之外定义的变量。

是不是看完这个定义感觉更加懵逼了?别急,我们来分析一下。

  • 闭包是一个函数

  • 闭包可以使用在它外面定义的变量

  • 闭包存在定义该变量的作用域中

  • 好像有点清晰了,但是使用在它外面定义的变量是什么意思,我们先来看看变量作用域。

    变量作用域

    变量可分为全局变量和局部变量。全局变量的作用域就是全局性的,在 js 的任何地方都可以使用全局变量。在函数中使用 var 关键字声明变量,这时的变量即是局部变量,它的作用域只在声明该变量的函数内,在函数外面是访问不到该变量的。

    var func = function(){
     var a = 'linxin';
     console.log(a); 
     // linxin}func();console.log(a); 
     // Uncaught ReferenceError: a is not defined

    作用域相对比较简单,我们不多讲,来看看跟闭包关系比较大的变量生存周期。

    变量生存周期

    全局变量,生命周期是永久的。局部变量,当定义该变量的函数调用结束时,该变量就会被垃圾回收机制回收而销毁。再次调用该函数时又会重新定义了一个新变量。

    var func = function(){
     var a = 'linxin';
     console.log(a);}func();

    a 为局部变量,在 func 调用完之后,a 就会被销毁了。

    var func = function(){
     var a = 'linxin';
     var func1 = function(){
     a += ' a';
     console.log(a);
     }
     return func1;}var func2 = func();func2(); 
     // linxin afunc2(); 
     // linxin a afunc2(); 
     // linxin a a a

    可以看出,在第一次调用完 func2 之后,func 中的变量 a 变成 'linxin a',而没有被销毁。因为此时 func1 形成了一个闭包,导致了 a 的生命周期延续了。

    这下子闭包就比较明朗了。

  • 闭包是一个函数,比如上面的 func1 函数

  • 闭包使用其他函数定义的变量,使其不被销毁。比如上面 func1 调用了变量 a

  • 闭包存在定义该变量的作用域中,变量 a 存在 func 的作用域中,那么 func1 也必然存在这个作用域中。

  • 现在可以说,满足这三个条件的就是闭包了。

    下面我们通过一个简单而又经典的例子来进一步熟悉闭包。

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

    我们可能会简单的以为控制台会打印出 0 1 2 3,可事实却打印出了 4 4 4 4,这又是为什么呢?我们发现,setTimeout 函数时异步的,等到函数执行时,for循环已经结束了,此时的 i 的值为 4,所以 function() { console.log(i) } 去找变量 i,只能拿到 4。

    我们想起上一个例子中,闭包使 a 变量的值被保存起来了,那么这里我们也可以用闭包把 0 1 2 3 保存起来。

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

    当 i=0 时,把 0 作为参数传进匿名函数中,此时 function(i){} 此匿名函数中的 i 的值为 0,等到 setTimeout 执行时顺着外层去找 i,这时就能拿到 0。如此循环,就能拿到想要的 0 1 2 3。

    内存管理

    在闭包中调用局部变量,会导致这个局部变量无法及时被销毁,相当于全局变量一样会一直占用着内存。如果需要回收这些变量占用的内存,可以手动将变量设置为null。

    然而在使用闭包的过程中,比较容易形成 JavaScript 对象和 DOM 对象的循环引用,就有可能造成内存泄露。这是因为浏览器的垃圾回收机制中,如果两个对象之间形成了循环引用,那么它们都无法被回收。

    function func() {
     var test = document.getElementById('test');
     test.onclick = function () {
     console.log('hello world');
     }
     }

    在上面例子中,func 函数中用匿名函数创建了一个闭包。变量 test 是 JavaScript 对象,引用了 id 为 test 的 DOM 对象,DOM 对象的 onclick 属性又引用了闭包,而闭包又可以调用 test ,因而形成了循环引用,导致两个对象都无法被回收。要解决这个问题,只需要把循环引用中的变量设为 null 即可。

    function func() {
     var test = document.getElementById('test');
     test.onclick = function () {
     console.log('hello world');
     }
     test = null;}

    如果在 func 函数中不使用匿名函数创建闭包,而是通过引用一个外部函数,也不会出现循环引用的问题。

    function func() {
     var test = document.getElementById('test');
     test.onclick = funcTest;}function funcTest(){
     console.log('hello world');
     }

    文档

    关于JavaScript中闭包的详解

    关于JavaScript中闭包的详解:闭包是什么在 JavaScript 中,闭包是一个让人很难弄懂的概念。ECMAScript 中给闭包的定义是:闭包,指的是词法表示包括不被计算的变量的函数,也就是说,函数可以使用函数之外定义的变量。是不是看完这个定义感觉更加懵逼了?别急,我们来分析一下。闭包是一
    推荐度:
    标签: js 详解 javascript
    • 热门焦点

    最新推荐

    猜你喜欢

    热门推荐

    专题
    Top