欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  web前端

什么是 Javascript 的闭包

程序员文章站 2022-04-10 15:53:32
...
什么是闭包?

闭包是什么?闭包是Closure,这是静态语言所不具有的一个新特性。但是闭包也不是什么复杂到不可理解的东西,简而言之,闭包就是:闭包就是函数的局部变量集合,只是这些局部变量在函数返回后会继续存在。闭包就是就是函数的“堆栈”在函数返回后并不释放,我们也可以理解为这些函数堆栈并不在栈上分配而是在堆上分配,当在一个函数内定义另外一个函数就会产生闭包。

闭包 = 函数内部创建的函数(或者简称内部函数) + 该函数创建时所处环境信息

所以闭包并不等于匿名函数,虽然也有人称这些在函数内部创建的函数为闭包函数,但是我觉得其实并不准确。

我们看一下下面这段代码:

function init() {
    var name = "Zilongshanren"; // name 是在 init 函数里面创建的变量
    // displayName() 是一个内部函数,即一个闭包。注意,它不是匿名的。
    function displayName() {
        console.log(name);
    }
    //当 displayName 函数返回后,这个函数还能访问 init 函数里面定义的变量。
    return displayName;
}
var closure = init();
closure();
Zilongshanren
undefined

displayName 是一个在 init 函数内部创建的函数,它携带了 init 函数内部作用域的所有信息,比如这里的 name 变量。当 displayName 函数返回的时候,它本身携带了当时创建时的环境信息,即 init 函数里面的 name 变量。

闭包有什么作用?

在理解什么是闭包之后,接下来你可能会问:这东西这么难理解,它到底有什么用啊?

因为在 Js 里面是没有办法创建私有方法的,它不像 java 或者 C++有什么 private 关键字可以定义私有的属性和方法。 Js 里面只有函数可以创建出属于自身的作用域的对象,Js 并没有块作用域!这个我后面会再写一篇文章详细介绍。

编程老鸟都知道,程序写得好,封装和抽象要运用得好!不能定义私有的属性和方法,意味着封装和抽象根本没法用。。。

不能定义私有的东西,所有变量和函数都 public 显然有问题, Global is Evil!

闭包是我们的救星!

我们看一下下面这段代码:

var makeCounter = function() {
    var privateCounter = 0;
    function changeBy(val) {
        privateCounter += val;
    }
    return {
        increment: function() {
            changeBy(1);
        },
        decrement: function() {
            changeBy(-1);
        },
        value: function() {
            return privateCounter;
        }
    }
};
var counter1 = makeCounter();
var counter2 = makeCounter();
console.log(counter1.value()); /* Alerts 0 */
counter1.increment();
counter1.increment();
console.log(counter1.value()); /* Alerts 2 */
counter1.decrement();
console.log(counter1.value()); /* Alerts 1 */
console.log(counter2.value()); /* Alerts 0 */
0
2
1
0
undefined

这里面的 privateCounter 变量和 changeBy 都是私有的,对于 makeCounter 函数外部是完全不可见的。这样我们通过 makeCounter 生成的对象就把自己的私有数据和私有方法全部隐藏起来了。

这里有没有让你想到点什么?

哈哈,这不就是 OO 么?封装数据和操作数据的方法,然后通过公共的接口调用来完成数据处理。

当然,你也许会说,我用原型继承也可以实现 OO 呀。没错,现在大部分人也正是这么干的,包括我们自己。不过继承这个东西,在理解起来总是非常困难的,因为要理解一段代码,你必须要理解它的所有继承链。如果一旦代码出 bug 了,这将是非常难调试的。

扯远了,接下来,让我们看看如何正确地使用闭包。

如何正确地使用闭包?

闭包会占用内存,也会影响 js 引擎的执行效率,所以,如果一段代码被频繁执行,那么要谨慎考虑在这段代码里面使用闭包。

让我们来看一个创建对象的函数:

function MyObject(name, message)
 {    this.name = name.toString();  
   this.message = message.toString();   
    this.getName = function()
     {        return this.name;    };   
      this.getMessage = function() 
      {        return this.message;    };}
      var myobj = new MyObject();
var myobj = new MyObject();

每一次被调用生成一个新对象的时候,都会生成两个闭包。如果你的程序里面有成千上万个这样的 MyObject 对象,那么会额外多出很多内存占用。

正确的做法应该是使用原型链:

function MyObject(name, message) {
    this.name = name.toString();
    this.message = message.toString();
}
MyObject.prototype.getName = function() {
    return this.name;
};
MyObject.prototype.getMessage = function() {
    return this.message;
};
var myobj = new MyObject();

现在 MyObject 原型上面定义了两个方法,当我们通过 new 去创建对象的时候,这两个方法只会在原型上面存有一份。

闭包的性能如何?

闭包也是一个函数,但是它存储了额外的环境信息,所以理论上它比纯函数占用更多的内存,而且 Js 引擎在解释执行闭包的时候消耗也更大。不过它们之间的性能差别在 3%和 5%之间(这是 Google 上得到的数据,可能不是太准确)。

但是,闭包的好处肯定是大大的。多使用闭包和无状态编程,让 Bug 从此远离我们。

理解了闭包,你就能理解大部分 FP 范式的 Js 类库及其隐藏在背后的设计思想。当然仅有闭包还不够,你还需要被 FP 和无状态,lambda calculus 等概念*。

关于js闭包希望大家学完本篇内容之后就有所掌握。

相关推荐:

JS中关于闭包的简单解释

js中闭包和类如何理解

对js闭包的简单理解

以上就是什么是 Javascript 的闭包的详细内容,更多请关注其它相关文章!