JavaScript闭包(closure)的学习

柯里星轨
• 阅读 1317

昨天在看思否时,发现了一篇文章是关于JavaScript如何实现重载的,由于以前也和学长讨论过JavaScript是否能够重载,就点进去看了看,发现里面的两个方法的其中一个需要用闭包实现,就看了几篇博客学习了一下,顺便写篇博客加深一下印象。
(JavaScript重载的文章在这:https://segmentfault.com/a/11...

什么是闭包

  • 闭包的本质是一个函数
  • 闭包可以访问函数内部变量
  • 闭包的存在会使内部变量保留在内存中

这个可以说是闭包比较容易让人理解又比较全面的解释了,更通俗一些:当function里嵌套function时,内部的function可以访问外部function里的变量。

下面让我们来看一个例子:

function A(){
    function B(){
       console.log('Hello Closure!');
    }
    return B;
}
var C = A();
C();// Hello Closure!

上面就是一个最简单的闭包。

就下来让我们来看一下下面这个函数,他是不是一个闭包呢?

 function foo(x) {
  var tmp = 3;
  function bar(y) {
    alert(x + y + (++tmp));
  }
  bar(10);
}
foo(2);

答案是:并不是,重新看一下闭包的定义,就明白了:
JavaScript闭包(closure)的学习

它能吗?明显不能,当你return的是内部function时,就是一个闭包。

function foo(x) {
  var tmp = 3;
  return function (y) {
    alert(x + y + (++tmp));
  }
}
var bar = foo(2); // bar 现在是一个闭包
bar(10);

至于能保存的原因,看了看网友的解释:

由于内部函数嵌套在foo中,导致内部函数的作用域链上添加了foo的作用域;而当内部函数被返回后,也要保证其作用域链有效,因此,函数foo的作用域不得不被保留在内存中以供内部函数访问。

闭包的作用

接下来来谈谈闭包的作用,初学者刚接触时肯定是一脸懵逼,闭包的用处究竟是什么,下面就来谈一谈。

一.模仿块级区域

首先简单举个例子来,解释一下什么是块级作用域:

function A(num) {
    for (var i = 0; i < num; i++) {
      num++;
    }
    console.log(i)
  }

在这个简单的函数中,变量i是在for循环中定义的,如果是在C++或者Java中,这样定义的变量,一旦循环结束,变量也就随之销毁,i的作用范围只在循环这个小块,就称为块级作用域。在javascript中,没有这样的块级作用域,前面一篇文章已经提到,变量是定义在函数的活动对象中的,因此,从定义i开始,在函数内部可以随时访问它。
这样的坏处显而易见:由于javascript不会告诉你变量是否已经被声明,容易造成命名冲突,如果是在全局环境定义的变量,就会污染全局环境,因此可以利用闭包特性来模拟块级作用域

明白了块级作用域,接下来看看js怎么实现的吧:

function A(num) {
    //下面是一个匿名立即执行函数
    //核心代码
   (funnction(){
    for(var i = 0; i<num; i++) {
      num++;
    }
    })()
    //核心代码结束
    console.log(i)//underfined
  }

使用这个就可以有效的避免全局污染,也许有人会对匿名立即执行函数为什么是一个闭包感到困惑,如果有这个问题可以点击这里查看

二.存储变量

闭包的另一个作用是可以保存外部函数的变量

function StorageVariable(){
    var x = 100;
    return {
        function(){
            return x
        }
    }
}

var test = StorageVariable();//运行StorageVariable函数,生成活动变量 x被test引用

这种写法可能会用在把一些不经常变动,但是计算比较复杂的值保存起来,就可以节省每次访问的时间.

三.封装私有变量

javascript中没有私有成员的概念,我们可以把函数当做一个范围,函数内的变量就是私有变量:

function Person(){
    var name = 'default';
    this.getName = function(){
        return name;
    }
    this.setName = function(value){
        name = value;
    }
}
var person = new Person()
console.log(person.getName())//default
console.log(person.setName('mike'))
console.log(person.getName())//mike

这样就可以像私有变量一样访问和改变person的name了。

总结

不得不说写博客总结对学习这种比较难的东西真的很有用,明明我昨天感觉自己已经大概弄明白了,但在写着写着的时候又陷入了困惑,虽然写完这个不敢说已经完全弄懂了,但至少比昨天强了,但要完全掌握还任重而道远,还得靠多使用。同时也得感谢

参考文章

js闭包的应用
让你分分钟理解 JavaScript 闭包
闭包,懂不懂由你,反正我是懂了
点赞
收藏
评论区
推荐文章
Karen110 Karen110
4年前
一篇文章带你了解JavaScript 函数闭包
大家好,我是前端进阶者。JavaScript变量属于本地或者全局范围,使用闭包可以让私有变量成为可能。一、全局变量一个函数可以访问所有定义在函数内部的变量。functionmyFunction()vara4;returnaa;但是函数也可以访问定义在函数之外的变量。vara4;//全局变量funct
徐小夕 徐小夕
4年前
前端进阶之从零到一实现单向 & 双向链表
前言前端工程师对于算法和数据结构这块的知识的掌握程度,是进阶高级工程师的非常重要的标志之一,为了总结一下数据结构和算法方面的知识,笔者今天继续把链表这一块的知识补上,也作为自己知识体系的一个梳理,笔者早在去年就写过一篇关于使用javascript实现二叉树和二叉搜索树的文章,如果感兴趣或者想进阶高级的朋友们可以参考学习一下:JavaScript中的二
Stella981 Stella981
4年前
JavaScript易错知识点整理
前言本文是我学习JavaScript过程中收集与整理的一些易错知识点,将分别从变量作用域,类型比较,this指向,函数参数,闭包问题及对象拷贝与赋值这6个方面进行由浅入深的介绍和讲解,其中也涉及了一些ES6的知识点。JavaScript知识点1.变量作用域vara1;functio
Stella981 Stella981
4年前
JavaScript原型深入浅出
不学会怎么处理对象,你在JavaScript道路就就走不了多远。它们几乎是JavaScript编程语言每个方面的基础。事实上,学习如何创建对象可能是你刚开始学习的第一件事。对象是键/值对。创建对象的最常用方法是使用花括号{},并使用点表示法向对象添加属性和方法。letanimal{}animal.name
Stella981 Stella981
4年前
Markdown语法讲解及MWeb使用教程
写了一个月的博客,忽然感觉Markdown编辑器比较好用,于是就下载了一个本地的Markdown编辑软件学习了一下,刚好软件里自带了一篇英文的指示文档,顺便翻译了一下,通过这个过程也大致熟悉了Markdown语法,以后都会用Markdown来写文章了。通过Markdown编辑器发布了几篇博客,发现以下几个标签比较常用:标题标签
Stella981 Stella981
4年前
JavaScript 作用域
在学习js的过程对闭包什么的,理解不好,偶然搜到这篇文章。豁然开朗,随翻译。Javacript中有一系列作用域的概念。对于新的JS的开发人员无法理解这些概念,甚至一些经验丰富的开发者也未必能。这篇文章主要目的帮助理解JavaScript中的一些概念如:scope,closure,this,namespace,functionscope,
Stella981 Stella981
4年前
CMake学习笔记四:usb_cam的CMakeLists解析
最近在学习cmake,在完整看了《cmake实践》一书后,跟着书上例程敲了跑了一遍,也写了几篇相关读书笔记,算是勉强基本入门了。所以找了usb\_cam软件包的CMakeLists.txt来进一步学习,在看懂这个例子之后,准备写篇博客记录一下,若有谬误还望指正。<br/1usb\_cam软件包简介现在市面上最
Stella981 Stella981
4年前
Javascript相关学习
JavaScript发现了一个不错的学习JavaScript的网站,就是MDN,具体见JavaScript参考(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fdeveloper.mozilla.org%2FzhCN%2Fdocs%2FWeb%2FJavaS
Stella981 Stella981
4年前
JavaScript函数——闭包
闭包概念只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁例子functionouter(){varlocalVal30;returnlocalVal;}
Stella981 Stella981
4年前
HTML5+CSS+JS 贪吃蛇demo
我写博客的主要目的就是温习所学的知识,自己以前写的游戏当然不能放过!这款网页版贪吃蛇是大一下册学习网页前端时老师教我们写的,由于那个时候初学网页前端,所以这款游戏是纯原生JavaScript写的,没有使用JQuery。重新看了一遍自己写的代码,大一的我真的太年轻了,一个注释都没有写,幸好这款游戏的逻辑不难,还能看得懂,补了一些注释,对一些细节加深了
Stella981 Stella981
4年前
JavaScript中call()与apply()有什么区别?
今天读《JavaScript权威指南》时发现其中有段代码用到了apply方法用于递归实现数组的展开。可是我不懂这个函数的用法,因此查了一下,将资料整理如下。Javascript的每个Function对象中有一个apply方法:function.apply(thisObj,argArray)还有一个类似功能的call方法: