【面试官】说说你对闭包的理解

说说你对闭包的理解

  • 闭包是什么
  • 闭包的三个特性
  • 优缺点
  • 应用场景
  • javascript的垃圾回收原理:
    • 通常情况下有两种实现方式
    • 垃圾回收原理的缺陷
    • GC优化策略

闭包是什么

  • 闭包就是能够读取其他函数内部变量的函数
  • 闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域

闭包的三个特性

  • 函数内再嵌套函数
  • 内部函数可以引用外层的参数和变量
  • 参数和变量不会被垃圾回收机制回收

优缺点

  • 使用闭包主要是为了设计私有的方法和变量
  • 闭包的优点是可以避免全局变量的污染,让这些变量始终保持在内存中,可以读取函数内部的变量,还可以就是,能够实现封装和缓存等,私有成员的存在
  • 缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。消耗内存、不正当使用会造成内存溢出的问题
  • 在js中,函数即闭包,只有函数才会产生作用域的概念

应用场景

  • 场景一:采用函数引用方式的setTimeout调用(和click一样)
    原生的setTimeout传递的第一个函数不能带参数,通过闭包可以实现传参效果。
function f1(a) {
    function f2() {
        console.log(a);
    }
    return f2;
}
var fun = f1(1);
setTimeout(fun,1000);//一秒之后打印出1
  • 场景二:沙箱模式可以将代码运行环境与外部环境隔离开来,防止互相干扰和污染。
  // 创建一个沙箱函数,接收一个配置对象作为参数
    function createSandbox(config) {
        // 在沙箱函数内部定义私有变量和方法
        var privateData = config.data;

        function privateMethod() {
            // 私有方法的实现
        }
        // 返回一个包含公共接口的对象
        return {
            // 公共方法
            publicMethod: function () {
                // 使用私有数据和私有方法进行业务逻辑处理
                console.log(privateData);
                privateMethod();
            }
        };
    }

    // 使用沙箱函数创建一个沙箱实例
    var sandbox = createSandbox({
        data: "私有数据"
    });

    // 调用沙箱实例中的公共方法
    sandbox.publicMethod();
  • 场景三
    封装私有变量  
    如下面代码:用js创建一个计数器
    function f1() {
        var sum = 0;
        var obj = {
            inc: function () {
                sum++;
                return sum;
            }
        };
        return obj;
    }
    let result = f1();
    console.log(result.inc(), '1');//1
    console.log(result.inc(), '2');//2
    console.log(result.inc(), '3');//3
function f1() {
    var sum = 0;
    function inc() {
        sum++;
        return sum
    }
    return inc;
}
let result = f1();
console.log(result(), '1');
console.log(result(), '2');
console.log(result(), '3');//3
function f1() {
    var sum = 0;
    function f2() {
        sum++;
        return f2;
    }
    //返回指定对象的原始值,若对象没有原始值,则将返回对象本身。
    f2.valueOf = function () {
        return sum;
    };
    f2.toString = function () {
        return sum + '';
    };
    return f2;
}
//执行函数f1,返回的是函数f2
console.log(+f1());//0
console.log(+f1()())//1
console.log(+f1()()())//2

javascript的垃圾回收原理:

Javascript具有自动垃圾回收机制(GC:Garbage Collecation)

  1. 在javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收:
  2. 如果两个对象互相引用,而不再被第三者所引用,那么这两个互相引用的对象也会被回收。

通常情况下有两种实现方式

标记清除

  • js中最常用的垃圾回收方式就是标记清除。

当变量进入环境时,例如,在函数中声明一个变量,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为“离开环境”。

引用计数

  • 跟踪记录每个值被引用的次数

当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1。如果同一个值又被赋给另一个变量,则该值的引用次数加1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减1。当这个值的引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。这样,当垃圾回收器下次再运行时,它就会释放那些引用次数为0的值所占用的内存。

垃圾回收原理的缺陷

和其他语言一样,javascript的垃圾回收机制策略也无法避免一个问题:自动垃圾回收机制时,停止响应其他操作,这是为了安全考虑,而Javascript的GC在100ms甚至以上,对一般的应用还好,但对于JS游戏,动画对连贯性要求比较高的应用,就麻烦了。这就是新引擎需要优化的点:避免GC造成的长时间停止响应。

GC优化策略

  • 分代回收(Generation GC)

这个和Java回收策略思想是一致的。目的是通过区分“临时”与“持久”对象;多回收“临时对象”区(young generation),少回收“持久对象”区(tenured generation),减少每次需遍历的对象,从而减少每次GC的耗时

  • 增量GC

这个方案的思想很简单,就是每次处理一点,下次再处理一点,如此类推

你可能感兴趣的:(javascript,前端,开发语言)