JavaScript函数之闭包

作者: 微语博客 | 来源:发表于2021-07-31 00:14 被阅读0次

什么是闭包

闭包是JavaScript的难点,闭包产生的原因也是因为函数作用域的特性,函数作用域的内容可以回顾上一篇文章JavaScript函数之作用域。闭包是什么呢,很多文档资料对闭包的讲解也是非常的抽象,比如引用Mozilla对闭包的解释:一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。简单的理解是:闭包其实是一个被引用的函数作用域。这个作用域是函数的一个私有空间,由于私有空间的变量被引用,从而形成闭包不让它销毁。

回顾作用域

在JavaScript中,作用域无非两种:局部和全局作用域。作用域的特点也很明显,内层可以访问外层的作用域。比如下面的示例:

function myFun() {
    var num = 10;
    function inFun(){
        console.log(num);
    }
    inFun();//10
}
myFun();

当执行外层函数myFun时,该函数产生了一个内部变量num和一个内部函数inFun,所以在myFun函数外部无法访问到内部的作用域,原因是作用域创建的顺序有先后。同理,嵌套函数也是一样。

闭包

上面的示例中,myFun的嵌套函数inFun执行后成功输出了num的值,这是我们意料之中的事,因为嵌套函数可以访问外部函数的作用域,但是如果我们要在myFun外面执行inFun函数呢,看下面的例子

function myFun() {
    var num = 10;
    function inFun(){
        console.log(num);
    }
    return inFun;
}
var pubFun = myFun();
pubFun();//10

该示例中我们没有直接调用inFun函数,而是将它作为返回值返回了。在外层定义了一个全局变量pubFun,其值为myFun函数的调用,注意这里在声明变量pubFun时已经调用了myFun函数,所以再执行pubFun的时候输出了num的值。

在本示例中,由于myFun执行完毕,num变量可能会被回收销毁,但是由于内部函数对其有引用,所以myFun函数形成了一个闭包,阻止局部变量被销毁,所以闭包可以理解为是一个作用域,包括该作用域的所有引用。

计数器

再看一个闭包的示例:

function add() {
    var num = 0;
    function addx(x){
        return num+=x;
    }
    return addx;
}
var myAdd = add();
console.log(myAdd(1));//1
console.log(myAdd(1));//2
console.log(myAdd(1));//3

由于闭包,num变量不会被销毁或重置,所以每次执行都会累加,这样就形成了计数器。我们也可以让它的计数梯度为其它的值,比如下面:

function add() {
    var num = 0;
    function addx(x){
        return num+=x;
    }
    return addx;
}
var myAdd = add();
console.log(myAdd(2));//2
console.log(myAdd(2));//4
console.log(myAdd(2));//6

当然,这样的应用就有很多了,其核心就是JS函数形成的闭包。

闭包模拟私有方法

学过Java的同学都知道,Java可以用private关键字来修饰私有方法,而原生的js并没有提供支持,我们可以使用闭包来模拟私有方法,私有方法只能被同一个类所调用。

function math(x) {
    var num = 0;
    return {
        add : function (y) {
            return x + y;
        },
        multi : function (y) {
            return x * y;
        }
    };
}
var myMath = math(5);
console.log(myMath.add(5));//10
console.log(myMath.multi(5));//25

例子简单,够用就好,不过这个示例还就可以使用立即执行函数优化,下一篇文章讲解立即执行函数

闭包引发的性能问题

因为闭包中的作用域引用无法释放,大量的使用闭包会严重的消耗内存,如果不是特定任务需要使用闭包,在其它函数中创建函数不是一个明智选择。比如下面的例子:

function MyObj(name){
    this.name = name.toString();
    this.getName = function(){
        return this.name;
    }
}

类似这种示例,每次构造器被调用时,方法都会被重新赋值一次。应该关联于对象的原型,而不是定义到对象的构造器中。

function MyFun(name){
    this.name = name.toString();
}
MyFun.protoype = {
    getName : function(){
        return this.name;
    }
}

但是也不建议重新定义原型,而是推荐在原型对象上添加原型方法。

function MyFun(name){
    this.name = name.toString();
}
MyFun.protoype.getName = function(){
    return this.name;
}

这里就涉及到构造函数和原型的知识点了,先混个眼熟吧。

相关文章

  • 闭包

    原文出处 JavaScript深入之闭包 定义 MDN 对闭包的定义为: 闭包是指那些能够访问自由变量的函数。 那...

  • JavaScript:了解闭包

    闭包 什么是闭包? 闭包就是能够读取其他函数内部变量的函数。由于在Javascript语言中,只有函数内部的子函数...

  • JavaScript----闭包

    javascript之闭包 闭包的概念     闭包(closure)是 JavaScript 的一种语法特性。 ...

  • 作用域闭包

    概览 背景知识:JavaScript内存管理、JavaScript作用域。 内容 1 闭包定义 闭包:当函数可以记...

  • JavaScript 作用域

    概览 背景知识:JavaScript内存管理、JavaScript作用域。 内容 1 闭包定义 闭包:当函数可以记...

  • python函数之闭包

    目录 python函数之闭包什么是闭包python中的namespace闭包的条件闭包的优点 python函数之闭...

  • 闭包、定时器

    问答 1.什么是闭包?有什么作用? 闭包闭包就是能够读取其他函数内部变量的函数。在JavaScript中,只有函数...

  • 闭包的理解

    什么是闭包,闭包的用途是什么? 闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部...

  • 闭包(closure)

    闭包是函数和声明该函数的词法环境的组合。MDN MDN上的栗子 JavaScript中的函数会形成闭包。 闭包是由...

  • JavaScript 闭包问题

    1.闭包的概念 JavaScript中什么是闭包?首先我们要知道在JavaScript中,函数中声明变量函数外是无...

网友评论

    本文标题:JavaScript函数之闭包

    本文链接:https://www.haomeiwen.com/subject/nqkhvltx.html