闭包的全面解析

418 阅读2分钟

什么是闭包

一般我们说有有个 function a 里面包含并返回里 function b 这个函数 b 就是闭包函数。闭包可以重用一个对象,并保护对象不被串改和污染。

function foo() {
    let a = 1;
    return function far() {
        console.log('-----------------------------', a);
    }();
}
foo()

作用域和作用域链

作用域:就是在代码运行的过程中,有些变量,函数,对象有自己独立的可访问性,例如上例中的 变量a在函数foo中才能访问,在函数外部是不能访问的。函数作用域形成了一个独一的范围,保护了域内的变量,有效的防止了变量污染。

作用域链:通俗来说就是在作用域中,访问变量,遵循就近原则。变量的查找,会一层一层向上寻找,找到就停止,找不到就报错,新城了一个链条。

let a = 3;
function foo() {
    let a = 1;
    let b = 2;
    return function far() {
        return function result() {
            console.log('-----------------------------', a); 
        }();
    }();
}
foo()

// ----------------------------- 1

let a = 3;
function foo() {
    let b = 2;
    return function far() {
        return function result() {
            console.log('-----------------------------', a); 
        }();
    }();
}
foo()

// ----------------------------- 3

在这个例子中如果在foo里有变量a直接得到1,若果没有就向上寻找得到3,如果顶层中也没有就会报错。

闭包的原理

根据js的执行机制,在运行程序的时候会创建一个ao:active object 是函数运行的时候创建的临时活动对象。里面包括了所有的局变量,参数,this等。在运行上下文的时候就会被销毁,被垃圾回收机制回收。所以为了有些数据不被销毁,就要使用闭包。

let a = 3;
function foo() {
    let a = 1;
    let b = 2;
    return function far() {
       return a;
    };
}

function fn1() {
    let res = foo();
    console.dir(res)
    
}
fn1()

闭包被使用的变量a就没有被回收。

闭包的使用

因为闭包可以保存变量等原因,闭包被运用在防抖和截流中,因为闭包可以保护内部变量,也常用来模拟对象的私有写法。

function fn1() {
    let a = 0;
    let b = 0;
    return {
        add: function() {
            a++;
        },
        sub: function() {
            a--;
        },
        val: function() {
            return a;
        }
    }
}

let res1 = fn1();
let res2 = fn1();

console.log('-----------------------------', res1.val());
res1.add()
res1.add()
console.log('-----------------------------', res1.val());
console.log('-----------------------------', res2.val());


// ----------------------------- 0
// ----------------------------- 2
// ----------------------------- 0

闭的缺点

因为闭包能保护变量,导致变量不能被js的垃圾回收机制及时回收,容易占用内存,消耗资源,产生内存泄漏。所以不能滥用。