什么是JavaScript闭包

MDN对闭包的定义是:函数与对其状态即词法环境(lexical environment)的引用共同构成闭包(closure)。也就是说,闭包可以让你从内部函数访问外部函数作用域。在JavaScript,函数在每次创建时生成闭包。
闭包:内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。
通俗来讲 一个内部函数访问外部函数局部作用域内的变量 就产生了闭包
作用:延申变量的作用范围 ,使局部变量常驻在内存中不被销毁
缺点:变量不被销毁,发生内存泄漏

我们先通过一个错误的例子了解局部作用域和垃圾回收机制

    function func() {
        var num = 10;
	console.log(num);	
    }
    func();//输出10
    console.log(num);//报错 num is not defined

结论:在一个函数的外部无法访问函数内部作用域定义的变量 即函数的局部作用域。而在函数内部,func函数后 1.定义变量 2.被console.log 输出 3.被调用之后 退出函数 变量i失去引用 转而被当垃圾回收。
在javascript中,如果一个对象不再被引用,那么这个对象就会被垃圾回收机制回收;

再来看一个简单的闭包案例

   // 内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。
    function fn() {
        var str = "这是一段字符!";
        return function () {
            return str;
        }
    }
    let f =fn();
    console.log(f());//输出字符串 被返回的方法外部访问了fn函数局部作用域内的变量str 产生了闭包
    // f = "这是一段字符!";
    // f()函数称为 闭包函数

闭包函数:声明在一个函数中的函数,叫做闭包函数。
结论:被当作返回值的方法f 在fn()方法的局部作用域中访问了str变量产生了闭包,同时我们在fn()函数外部通过变量 f 函数接收了返回值,f = str,成功访问了函数局部作用域内的srt变量; 变相的 srt变量也延申了其值到全局;

两个案例了解闭包的作用

定义一个数组 三秒后打印其内容
var arr = [11,22,33];

//1.常规方法
   for (var i = 0;i{
            console.log(arr[i]);//打印输出
        },3000)
   }
//

结果:报错
undefined*3
原因:for循环是同步函数,而timeout的回调函数是一个异步函数,for循环执行完成之后, 其中的变量 i 已经被后续for循环的i++操作重新赋值 现在的值为3,导致报错。
解决方案:通过闭包 对每次for循环产生变量i值进行引用 产生闭包作用域 保留变量存活状态 但是内存中增加了 i=0,i=1,i=2;四个值 产生内存溢出。

//2.采用闭包方式
   for (var i = 0;i{
                console.log(arr[i]);//打印输出
            },3000)
        })(i)
	//Timeout中的回调方法访问了立即函数中的变量 i 产生闭包
    }

结果:
[0,1,2,3]
正常输出,延申变量i的使用范围 产生闭包

下面再来看一个经典案例

点击三个按钮 获取其索引值

立即执行函数

js立即执行函数可以让你的函数在创建后立即执行,可以让你的函数在定义后立即被执行,这种模式本质上就是函数表达式(命名的或者匿名的),在创建后立即执行。

常见方式

   //1.加括号
    (function (传值) {
        
    })(传值)


   //2.加特殊符号 +-x~! void  new都可以
    !function (str) {
      console.log(str)
    }("这是字符!")

作用:
1.创建一个独立的作用域。内部变量外部函数无法访问。
2.避免其它全局变量污染,函数为匿名函数。
3.使用作用域外的变量可通过参数传值进行引用。

你可能感兴趣的:(什么是JavaScript闭包)