闭包

110 阅读3分钟

简介

闭包现象是JS中一个特色但是又比较难的知识点,此外很多高级的应用程序都是依靠闭包来实现的,所以它的重要性不言而喻。简单点来说,闭包的作用就是把函数的内部和外部建立起联系。对于初学者而言呢,我们要先学会读懂代码,再去慢慢尝试自己写闭包。想要更好的理解闭包,就得理清JS中变量的作用域问题

  • 全局变量

    1.函数外部定义,全局范围有效

    2.始终保存在内存中,随着程序的执行完毕(页面关闭)而销毁

  • 局部变量

    1.函数内部定义,在函数内部有效

    2.当函数执行结束后,就会销毁

闭包的主要用途

  • 让函数外部能够获取到函数内部的变量

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

实例:

//让函数外部能够得到函数内部的变量
function outside(){         
    var num1=10
    function inside(){
        return num1
    }
    return inside
}
var n=outside()()   //相当于var a=outside()接收返回的inside,var n=a()接收返回的num1;
console.log(n)

//让函数的局部变量一直存在于内存当中
function fn1(){
    var num1=10
    add=function(){ //这里的add是不能直接访问num的,每调用一次add方法都会找上一次的num值,再做++操作
        num1++
        console.log(num1)
        console.log("add")
    }
    function fn2(){
        console.log(num1)
    }
    return fn2
}

闭包存在的缺点

闭包可以让函数外部拿到函数内部的变量,也能将函数内部的变量始终保存在内存中。 这是闭包的优点,也是它的缺点。 因为一旦滥用闭包就会让内存消耗变大,情况严重时可能会造成内存泄露。

对应的解决办法

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

记录的几个比较经典的面试题:

面试题1

var name ='window'
var obj={
    name:'obj'
    getName:function(){
        return function(){
            return this.name
            //就是考察this的指向问题,确定作用域,对象是没有作用域的,只有函数和<script>有作用域
        }
    }
}
alert(obj.getName()())  //window

面试题2

var name='window'
var obj={
    name:'obj'
    getName:function(){
        var _this=this      //这一步零时存储了this的指向,(对象方法,指向对象)
        return function(){
            return _this.name
        }
    }
}
alert(obj.getName()())  //obj

面试题3

function getSum(num1){
    return function(num2){
        return num1+num2    //函数自身没有num1所以会往上层找,找到num1做加法运算
    }
}
let n=getSum(5)(10)
console.log(n)      //15

附加题

function fn(n,o){
    console.log(n,o)
    return {
        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(3);       //3,0
    
    var b = fn(0).fn(1).fn(2).fn(3);//链式调用,也可以拆写
    等价于:var b=fn(0)     //0,undefined
            var c=b.fn(1)   //1,0
            var d=c.fn(2)   //2,1
            var e=d.fn(3)   //3,2
    
    var c = fn(0).fn(1);//拆写成,var a=fn(0);var b=a.fn(1) 1,0
    (注意:我这里就的结果就少了一个0,undefined,虽然它写的是链式调用的方式,但是我们要清楚执行的流程,和每一步的返回值,不能遗漏)
    c.fn(2);            //相当于b.fn(2) 2,1
    c.fn(3);            //相当于b.fn(3) 3,1