JS 闭包

586 阅读3分钟

闭包是属于比较高级的 js 变成范畴,最近在重新学习 JS 基础知识,尝试解释一下闭包。

概念

闭包函数:声明在一个函数中的函数,叫做闭包函数。 像这样:

function parentFn(){
    return sonFn(){
        console.log(111) 
    }
}
parentFn()()  // 111

一个知识点:只有使用 () 函数才会执行。

闭包:内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。

这里所谓的寿命终结是指,当函数执行完成以后将会被内存回收机制收回。这里收回的也是函数在执行时开辟的私有作用域。

像这样:

function parentFn(){
    var num = 1;
    return sonFn(){
        return num 
    }
}

为什么会产生闭包

JS 本身为了避免解释器过量消耗内存,造成系统崩溃, 自带有一套垃圾回收机制,垃圾回收机制能够检测到一个 对象是不是无用 的。检测到之后,就会把它占用的内存释放掉。但是实际工作中,我们也会需要一些变量不那么及时的被清理,所以就出现了闭包,用来达成这个效果。

另外,声明一个函数在全局形成了一个私有的作用域,所以我们有时候需要操作函数内(作用域)的变量就需要通过闭包来实现访问和修改的功能。

注意看重点,对象是不是无用的,那么怎样就无用呢??上面有一部分解释,函数执行完以后即被回收,我们来看下面的例子。

var add = (function{
    var num = 1;
    return sonFn(){
        return num ++
    }
})()

add()   // 1
add()   // 2

解释一下,自执行匿名函数被执行了,所以要销毁,但是它内部的一个变 numsonFn 所使用,sonFn 还没有执行,所以导致 num 不会被释放,我们知道函数对象和普通对象的区别就是不能缓存变量,这个例子因为内部引用所以不会被回收,所以导致这个 num 一直存在。

闭包能干什么

一直信奉一点,技术是为了解决问题而存在的,所以用技术来解决实际的问题,的才是技术存在的意义。

1. 作为私有空间,防止变量污染,有助于模块化代码

var foo = (function(){
    var secret = 'secret';// “闭包”内的函数可以访问 secret 变量,而 secret 变量对于外部却是隐藏的
    return{
        get_secret: function(){ // 通过定义的接口来访问 secret
            return secret;
        },
        new_secret: function(new_secret){    // 通过定义的接口来修改 secret
            secret = new_secret;
        }
    };
}());

foo.get_secret();               // 得到 'secret'
foo.secret;                     // Type error,不能访问
foo.new_secret('a new secret'); // 通过函数接口,我们访问并修改了 secret 变量
foo.get_secret();               // 得到 'a new secret'

2. 缓存变量值


function add() {
    var counter = 0;
    return counter += 1;
}
 
add();
add();
add();
 
// 计数器每次都是 1,函数执行一次既销毁。
// 使用闭包

function add() {
    var counter = 0;
    return function(){
        return counter += 1;
    }
}
var sum = add()

sum()   // 1
sum()   // 2
sum()   // 3

// 补充,sum是一个非纯函数