关于闭包

什么是闭包?

闭包:

一个函数和词法环境的引用捆绑在一起,这样的组合就是闭包

就是一个函数A,return其内部的函数B,被return出去的函数B能够在外部访问A函数内部的变量(定义在函数内部的函数)

这时候就形成了一个函数B的变量背包,A函数执行结束之后这个变量背包也不会被销毁

并且这个变量背包在A函数外部只能通过B函数来访问(闭包就是一座将函数内部和外部连接起来的桥梁)

原理:

作用域链,当前作用域链可以访问上级作用域中的变量

闭包解决的问题:

能够让函数作用域中的变量在函数执行结束之后不被销毁,同时也能在函数外部可以访问函数内部的局部变量。

闭包带来的问题:

由于垃圾回收机制不会将闭包中的变量销毁,内存消耗会很大,所以不能滥用闭包,否则会造成网页性能问题,

也可能导致内存泄露,内存泄露积累多了就容易导致内存溢出(解决办法是在退出函数之前,将不使用的局部变量全部删除)

闭包的主要作用:

模仿块级作用域

已知数组var arr = ['a','b','c','d','e','f'],每过1秒打印一下数组中的值:

未有块级作用域时:setTimeout属于异步任务,for循环结束后,每秒输出的都为 'e'

 

var arr = ["a", "b", "c", "d", "e"];
for (var i = 0; i < arr.length; i++) {
    var item = arr[i];
    setTimeout(function() {
      console.log(item);
    }, 1000 * (i + 1));
}

 

ES5:借助IIFE(弥补JS在scope方面的缺陷)

 

var arr = ["a", "b", "c", "d", "e"];
for (var i = 0; i < arr.length; i++) {
    (function(j){
        var item = arr[j];
        setTimeout(function() {
            console.log(item);
        }, 1000 * (j + 1));
    })(i);
}    

 

ES6:let、const块级作用域

 

var arr = ["a", "b", "c", "d", "e"];
for (let i = 0; i < arr.length; i++) {
    const item = arr[i];
    setTimeout(function() {
        console.log(item);
    }, 1000 * (i + 1));
}        

 

实现柯里化

柯里化是一种转换,将 f(a,b,c) 转换为可以被以 f(a)(b)(c) 的形式进行调用。

在构造函数中定义特权方法

有权访问私有变量、私有函数的公有方法就是特权方法

Vue中数据响应式Observe中使用闭包等

function defineRealive(target, key, value){
    return Object.defineProperty(target, key, {
        get(){
            console.log(`通过getter获取数据:${value}`);
            return value;
        },
        set(val){
            console.log(`通过setter设置数据:新值-${val};旧值-${value}`);
            // 形参也是一个普通的局部变量,只是可能我们平时使用的时候,一般不会对形参进行赋值操作,因为大部分情况,形参都是外部传入的数据,我们无需修改。
            // 这里就用到了闭包的原理,value是外层函数defineRealive的参数,而我们实际上使用value确是在内层的get或set方法里面
            // 这样就形成了一个闭包的结构了。根据闭包的特性,内层函数可以引用外层函数的变量,并且当内层保持引用关系时外层函数的这个变量
            // 不会被垃圾回收机制回收。那么,我们在设置值的时候,把val保存在value变量当中,然后get的时候再通过value去获取,这样,我们再访问
            // obj.name,无论是设置值还是获取值,实际上都是对value这个形参进行操作的。
            value = val;
        }
    });
}
 
let obj = {
    name: 'kiner',
    age: 20
};
 
Object.keys(obj).forEach(key=>defineRealive(obj, key, obj[key]));

obj.name = 'kanger';
obj.age = 18;
// 控制台输出:kanger 18
console.log(obj.name,obj.age);

 

内存泄露与内存溢出:

内存泄露是指程序中已动态分配的堆内存由于某种原因,程序未释放或无法释放,造成的内存浪费

导致程序运行速度减慢甚至系统崩溃等严重后果(即不再会被使用的对象的内存不能被回收)

内存泄后堆积的结果就是内存溢出

 

参考:

面试闭包题

Javascript柯里化

特权方法

Vue对于闭包的使用

posted @ 2022-05-04 22:08  Du9191  阅读(124)  评论(0编辑  收藏  举报