1. 闭包的概念
闭包就是能够读取其他函数内部变量的函数。但是在JS中,只有函数内部的子函数才能获取局部变量,所以闭包也可以理解成“定义在一个函数内部的函数”。
2. 使用闭包的原因
根据作用域链,我们知道父对象的所有变量,对于子对象都是可见的,反之不成立。
let a = 1; let b = 1; function fn() { let a = 2; function fn1() { let a = 3; // 变量的值,运用就近原则,先看自己,再看邻居,最后看全局 console.log(a+b); // 3+1=4 } fn1(); } fn();
那么现在,我们外部想要获取函数内部的局部变量,该如何操作呢?
这时,为了获取函数内部的局部变量,我们需要使用闭包。具体方法:在函数内部定义函数,并将该函数作为返回值。
function fn1() { let str = '真心不错'; // str是fn1函数中的局部变量 // 这里fn2这个函数就是闭包 return function() { console.log(str); } // 通过在函数内部定义一个函数,并把其作为返回值,将局部变量传出去 } let fn2 = fn1(); // 把fn1函数的返回值赋给变量fn2,其实相当于 let fn2 = function() {console.log(str);} 即一个函数表达式 fn2(); // 调用fn2后,就可以打印出str了
小总结:
目的:为了获取函数内部的局部变量;
方法:在函数内部定义函数,并将该函数作为返回值。
作用:延伸了变量的作用范围。
3. 闭包的缺点
(1)缺点1: 通常情况下,函数执行完后,函数里面定义的变量会被销毁。但是使用闭包后,会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能会导致内存泄漏。
(2)缺点2:★闭包会在父函数的外部,改变父函数内部变量的值(使用全局函数来改变局部变量的值)
// 定义一个全局的变量 let add; function fn1() { let num = 10; // 使用全局函数来改变局部变量的值 add = function() { num++; } return function fn2() { // 因为fn2一直在引用num这个变量,导致num这个变量一直没有被垃圾回收机制所回收,所以全局函数add可以对num这个局部变量进行累加 console.log(num + '\n'); } } let fn = fn1(); // 把fn1函数的返回值给fn,即此时fn=function() {cosole.log(num);} fn(); // 调用函数fn,即打印出num的值10 add(); // 调用add函数,此时会导致num自加,即num变成了11 fn(); // 再次调用函数fn,此时打印出的num的值即为11,从而改变了函数内部变量的值
闭包具有一定积极的意义,但是同时也存在一些比较致命的缺点,所以在实际开发中要慎重使用,避免出现不必要的问题。