JavaScript进阶(三)闭包原理与用法详解


Posted in Javascript onMay 09, 2020

本文实例讲述了JavaScript闭包原理与用法。分享给大家供大家参考,具体如下:

为了更好的理解,在阅读此文之前建议先阅读上一篇《JavaScript词法作用域与作用域链》

1.什么是闭包

闭包的含义就是闭合,包起来,简单的来说,就是一个具有封闭功能与包裹功能的结构。所谓的闭包就是一个具有封闭的对外不公开的,包裹结构,或空间。

在JS中函数构成闭包。一般函数是一个代码结构的封闭结构,即包裹的特性,同时根据作用域规则只允许函数访问外部的数据,外部无法访问函数内部的数据,即封闭的对外不公开的特性,因此说函数可以构成闭包。

概括:闭包就是一个具有封闭与包裹功能的结构。函数可以构成闭包。函数内部定义的数据函数外部无法访问,即函数具有封闭性;函数可以封装代码即具有包裹性,所以函数可以构成闭包。

2.闭包有什么用(解决什么问题)?

  1. 闭包不允许外部访问
  2. 要解决的问题就是间接访问该数据

函数就可以构成闭包,要解决的问题就是如何访问到函数内部的数据

function foo () {
 var num = 123;
 return num;
}
var res = foo();
console.log( res ); // =>123

这里的确是访问到函数中的数据了。但是该数据不能第二次访问,因此第二次访问的时候又要调用一次foo,表示又有一个新的num = 123出来了。

在函数内的数据,不能直接在函数外部访问,那么在函数内如果定义一个函数,那么在这个函数内部中是可以直接访问的

function foo() {
 var num = Math.random();
 function func() {
  return mun;
 }
 return func;
}
var f = foo();
// f 可以直接访问这个 num
var res1 = f();
var res2 = f();

我们使用前面学习的绘制作用域链结构图的方法来绘制闭包的作用域链结构图,如下:

JavaScript进阶(三)闭包原理与用法详解

3.闭包使用举例

如何获得超过一个数据

function foo () {
 var num1 = Math.random();
 var num2 = Math.random();
 return {
  num1: function () {
   return num1;
  },
  num2: function () {
   return num2;
  }
 }
}

如何完成读取一个数据和修改这个数据

function foo () {
 var num = Math.random();
 return {
  get_num : function () {
   return num;
  },
  set_num: function( value ) {
   return num = value;
  }
 }
}

4.基本的闭包结构

一般闭包的问题就是要想办法简洁的获取函数内的数据使用权,那么我们就可以总结出一个基本的使用模型。

  1. 写一个函数,函数内部定义一个新函数,返回新函数,用新函数获得函数内的数据
  2. 写一个函数,函数内部定义个一个对象,对象中绑定多个函数(方法),返回对象,利用对象的方法访问函数内的数据

5.闭包的基本用法

闭包是为了实现具有私有访问空间的函数的

带有私有访问数据的对象

function Person() {
 this.name = "张三";
 // setName( '' )
}

所有的私有数据,就是说只有函数内部可以访问的数据,或对象内部的方法可以访问的数据

最简单的实现:

function createPerson() {
 var __name__ = "";
 return {
  getName: function () {
   return __name__;
  },
  setName: function( value ) {
   // 如果不姓张就报错
   if ( value.charAt(0) === '张' ) {
    __name__ = value;
   } else {
    throw new Error( '姓氏不对,不能取名' );
   }
  }
 }
}
var p = createPerson();
p.set_Name( '张三丰' );
console.log( p.get_Name() );
p.set_Name( '张王富贵' );
console.log( p.get_Name() );

带有私有数据的函数

var func = function () {}
function func () {}
var foo = (function () {
 // 私有数据
 return function () {
  // 可以使用私有的数据
  ...
 };
});

6.闭包基本模型

对象模型

function foo () {
 // 私有数据
 return {
   method : function(){
    // 操作私有数据
   }
 }
}

函数模型

function foo(){
 // 私有数据
 return function(){
   // 可以操作私有数据
 }
}

7.沙箱模式(闭包应用的一个典范)

7.1 沙箱的概念

沙盘与盒子,就可以在一个笑笑的空间内模拟显示世界,特点是执行效果与现实世界一模一样,但是在沙箱中模拟与现实无关.

7.2 沙箱模式

沙箱模式就是一个自调用函数,代码写到函数中一样会执行,但是不会与外界有任何的影响

例如,在jQuery中

(function () {
 var jQuery = function () { // 所有的算法 }
 // .... // .... jQuery.each = function () {}
 window.jQuery = window.$ = jQuery;
})();
$.each( ... )

8.带有缓存功能的函数

以 Fibonacci 数列为例,改进传统计算斐波那契数列方法
我们来回顾一下传统递归方式求斐波那契数列方法,我们定义一个count变量来查看递归了多少次:

var count = 0;
function fibo( n ){
 count++;
 if( n ==0 || n == 1 ) return 1;
 return fibo( n - 1 ) + fibo( n - 2 );
}
fib1( 20 );
console.log( count1 );
// 5: 15
// 6: 25
// ...
// 20: 21891

当 n = 5 式,count = 15,当时当 n = 20 的时候,count就达到惊人的21891次,性能太低了

性能低的原因是 重复计算。如果每次将计算的结果存起来

  • 那么每次需要的时候先看看有没有存储过该数据,如果有,直接拿来用。
  • 如果没有再递归,但是计算的结果需要再次存储起来,以便下次使用

改进版:

var data = [ 1, 1 ];
var count = 0;
function fibo( n ) {
 count++;
 var v = data[ n ];
 if( v === undefined ){
   v = fibo( n - 1 ) + fibo( n - 2 );
   data[ n ] = v;
 }
 return v;
}
fibo( 100 );
console.log( count ); // 199

改进之后, n = 100的时候也才199次,大大提高了性能。

9.闭包的性能问题

函数执行需要内存,那么函数中定义的变量,会在函数执行结束后自动回收,凡是因为闭包结构的,被引出的数据,如果还有变量引用这些数据的话,那么这些数据就不会被回收。

因此在使用闭包的时候如果不适用某学数据了,一定要赋值一个null

var f = (function () {
 var num = 123;
 return function () {
  return num;
 };
})();
// f 引用着函数,函数引用着变量num
// 因此在不适用该数据的时候,最好写上
f = null;

感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.3water.com/code/HtmlJsRun测试上述代码运行效果。

更多关于JavaScript相关内容可查看本站专题:《JavaScript常用函数技巧汇总》、《javascript面向对象入门教程》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》及《JavaScript数学运算用法总结》

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
js判断是否为数组的函数: isArray()
Oct 30 Javascript
JS复制到剪贴板示例代码
Oct 30 Javascript
javascript数组去重的方法汇总
Apr 14 Javascript
JavaScript图片轮播代码分享
Jul 31 Javascript
js简单实现标签云效果实例
Aug 06 Javascript
基于javascript显示当前时间以及倒计时功能
Mar 18 Javascript
实例分析浏览器中“JavaScript解析器”的工作原理
Dec 12 Javascript
js实现登录验证码
Dec 22 Javascript
Angualrjs和bootstrap相结合实现数据表格table
Mar 30 Javascript
使用express+multer实现node中的图片上传功能
Feb 02 Javascript
js遍历详解(forEach, map, for, for...in, for...of)
Aug 28 Javascript
Vue可自定义tab组件用法实例
Oct 24 Javascript
JavaScript进阶(二)词法作用域与作用域链实例分析
May 09 #Javascript
JavaScript进阶(一)变量声明提升实例分析
May 09 #Javascript
JavaScript面向对象核心知识与概念归纳整理
May 09 #Javascript
Vue列表如何实现滚动到指定位置样式改变效果
May 09 #Javascript
Node.js API详解之 util模块用法实例分析
May 09 #Javascript
Vue实现PC端靠边悬浮球的代码
May 09 #Javascript
Auto.JS实现抖音刷宝等刷视频app,自动点赞,自动滑屏,自动切换视频功能
May 08 #Javascript
You might like
PHP中遍历stdclass object的实现代码
2011/06/09 PHP
windows下配置apache+php+mysql时出现问题的处理方法
2014/06/20 PHP
利用google提供的API(JavaScript接口)获取网站访问者IP地理位置的代码详解
2010/07/24 Javascript
在网页中使用document.write时遭遇的奇怪问题
2010/08/24 Javascript
JS控制文本框textarea输入字数限制的方法
2013/06/17 Javascript
JS实现的用来对比两个用指定分隔符分割的字符串是否相同
2014/09/19 Javascript
js仿黑客帝国字母掉落效果代码分享
2020/11/08 Javascript
JS实现的N多简单无缝滚动代码(包含图文效果)
2015/11/06 Javascript
JavaScript基础语法之js表达式
2016/06/07 Javascript
JS简单获取当前年月日星期的方法示例
2017/02/07 Javascript
jQuery+C#实现参数RSA加密传输功能【附jsencrypt.js下载】
2017/06/26 jQuery
详解微信小程序Page中data数据操作和函数调用
2017/09/27 Javascript
Taro集成Redux快速上手的方法示例
2018/06/21 Javascript
webpack4实现不同的导出类型
2019/04/09 Javascript
vue中配置scss全局变量的步骤
2020/12/28 Vue.js
[56:38]DOTA2-DPC中国联赛正赛Aster vs Magma BO3 第一场 3月5日
2021/03/11 DOTA
原生python实现knn分类算法
2019/10/24 Python
python实现简单银行管理系统
2019/10/25 Python
keras之权重初始化方式
2020/05/21 Python
Python数据相关系数矩阵和热力图轻松实现教程
2020/06/16 Python
python 制作网站筛选工具(附源码)
2021/01/21 Python
python 实现Requests发送带cookies的请求
2021/02/08 Python
CSS3支持IE6, 7, and 8的边框border属性
2012/12/28 HTML / CSS
利用CSS3实现进度条的两种姿势详解
2017/03/21 HTML / CSS
HTML5 localStorage使用总结
2017/02/22 HTML / CSS
潘多拉珠宝英国官方网上商店:PANDORA英国
2018/06/12 全球购物
美国全球旅游运营商:Pacific Holidays
2018/06/18 全球购物
本科生求职简历的自我评价
2013/10/21 职场文书
物流管理应届生求职信
2013/11/07 职场文书
医科大学生毕业的自我评价分享
2013/11/12 职场文书
小学运动会入场式解说词
2014/02/18 职场文书
电子商务专业应届生求职信
2014/05/28 职场文书
现场活动策划方案
2014/08/22 职场文书
2014年妇幼卫生工作总结
2014/12/09 职场文书
2015年药品销售工作总结范文
2015/05/25 职场文书
部门主管竞聘书
2015/09/15 职场文书