关于闭包

115 阅读4分钟

闭包

闭包的概念

闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

要理解闭包的使用,我们先得了解JS变量的作用域

1 全局变量

  • 函数外部定义,全局范围有效
  • 始终保存在内存中,随着程序的执行完毕(页面关闭)而销毁

2 局部变量

  • 函数内部定义,函数内部有效
  • 随着函数的执行完毕而销毁

闭包的两个用途

让函数外部能够得到函数内部的变量。

让函数内部的变量始终保存在内存中。

//让函数外部能够得到函数内部的变量。
    function outSide() {
        var num = 10;
        function inSide() {
            return num;
        }
        return inSide;
    }
    var fn = outSide();
    var n = fn();
    console.log(n)

 //让函数内部的变量始终保存在内存中。
    function oSide() {
        var num = 10;
        add = function () {
            num++;
            console.log(num);
            console.log("add");
        }
        function iSide() {
            console.log(num);
        }
        return iSide;
    }
    var m = oSide();
    m();//10
    add();//12 (num本来为局部变量,但它没随着函数的结束而销毁,变成了类似于全局变量)
    add();//12
    m();//12

闭包的优缺点

闭包可以让函数外部拿到函数内部的变量,也能将函数内部的变量始终保存在内存中。

这是闭包的优点,也是它的缺点。

因为一旦滥用闭包就会让内存消耗变大,情况严重时可能会造成内存泄露。

闭包的解决办法

使用面向对象的思想进行代码的编写,将需要使用的函数和变量尽量封装到一个对象中去。

#面试题

在做面试题的时候我们先得再次复习一下JS中this的相关指向问题

  • 全局作用域下的this:指向 window;
  • 普通函数中的this:指向 window;
  • 事件回调函数中的this:指向事件的触发者;
  • 剪头函数中的this:指向函数定义时所在作用域的上下文;
  • 构造函数中的this:指向将来要被创建出来的对象;
  • 对象的方法中的this:指向当前对象;

闭包面试题一

 var name = 'window';
    var obj = {
        name:'obj',
        getName:function(){
            return function(){
                return this.name;
            }
        }
    };
    alert(obj.getName()());//window
//首先调用obj中的getName方法,返回值为funcfunction(){ return this.name;},而这个函数为普通函数,所以里面的this则指向的是window。

闭包面试题二

    var name = 'window';
    var obj = {
        name:'obj',
        getName:function(){
            var _this = this
            return function(){
                return _this.name;
            }
        }
    };
    alert(obj.getName()());//obj
//调用同上,但在函数中有定义一个变量用于存储obj的this,这样的话返回函数中的this则指的是obj对象。

闭包面试题三

var name = 'window';
    var obj = {
        name:'obj',
        getName:function(){
            return ()=>{
                return this.name;
            }
        }
    };
    alert(obj.getName()());// "obj"
//在此题中出现了箭头函数,所以我们得注意this指向的问题,由于是箭头函数所以this应该指向该函数定义时的作用域的上下文->也就是指向了obj。

闭包面试题四

var name = 'window';
    var obj = {
        name:'obj',
        getName:()=>{
            return function{
                return this.name;
            }
        }
    };
    alert(obj.getName()());// "window"
//在此题中也出现了箭头函数,所以我们还是根据箭头函数中的this指向确定this指向->这里的this就指向了window。值得注意就是obj对象的这组{}这里并不是一个作用域,往往有很多人会把它作为一个作用域得出"obj",但我们回过来想JS的作用域就两个:全局(一对script标签里),局部(一个函数的一对{}中)。所以就很容易得出"window"结果

闭包面试题五

// 函数柯里化
        function getSum(num1){// num1 = 5
            return function(num2){// num2 = 10
                return num1+num2;
            }
        }
        var a = getSum(5)(10);
        console.log(a);//15

##终极面试题(堪称闭包职业生涯的顶尖水平)

终极面试题 part1

        // var n=0; var o;
        function fn(n,o){// n=1,o=0
            console.log(n,o);// 0,undefined  1,0   2,0
            return {
                fn:function(m){// m=2
                    return fn(m,n)// fn(2,0)
                }
            }
        }
        /*
            n = 0
            a = {
                fn:function(m){
                    return fn(m,n)
                }
            }
        */
        var a = fn(0); // 0,undefined
        a.fn(1); //1,0
        a.fn(2); //2,0
        a.fn(10);//10,0

终极面试题 part2

 // n=0,o
        function fn(n,o){// n=1,o=0   n=2,o=1   n=3,o=2
            console.log(n,o);// 
            return {
                fn:function(m){// m=3
                    return fn(m,n)// fn(3,2)
                }
            }
        }
        var a = fn(0)// 0,undefined
        var b = a.fn(1)// 1,0
        var c = b.fn(2)// 2,1
        c.fn(3);// 3,2
        /*
            n = 0
            a = {
                fn:function(m){// 
                    return fn(m,n)// 
                }
            }
            n = 1
            b = {
                fn:function(m){// 
                    return fn(m,n)// 
                }
            }
            n = 2
            c = {
                fn:function(m){// 
                    return fn(m,n)// 
                }
            }
        */

终极面试题 part3

 // n=0,o
        function fn(n,o){// n=1,o=0
            console.log(n,o);// 
            return {
                fn:function(m){//
                    return fn(m,n)// fn(2,1)
                }
            }
        }
        var a = fn(0);// 0,undefined
        var b = a.fn(1); // 1,0
        b.fn(2); // 2,1
        b.fn(3); // 3,1