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 相关文章推荐
JavaScript和JQuery实用代码片段(一)
Apr 07 Javascript
用jquery方法操作radio使其默认选项是否
Sep 10 Javascript
jquery序列化form表单使用ajax提交后处理返回的json数据
Mar 03 Javascript
jQuery中innerHeight()方法用法实例
Jan 19 Javascript
jquery判断checkbox是否选中及改变checkbox状态的实现方法
May 26 Javascript
终于实现了!精彩的jquery弹幕效果
Jul 18 Javascript
BootStrap Validator 版本差异问题导致的submitHandler失效问题的解决方法
Dec 01 Javascript
three.js绘制地球、飞机与轨迹的效果示例
Feb 28 Javascript
js实现3D图片展示效果
Mar 09 Javascript
react路由配置方式详解
Aug 07 Javascript
如何利用@angular/cli V6.0直接开发PWA应用详解
May 06 Javascript
重置Redux的状态数据的方法实现
Nov 18 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
phpMyAdmin 安装教程全攻略
2007/03/19 PHP
php另类上传图片的方法(PHP用Socket上传图片)
2013/10/30 PHP
浅谈Coreseek、Sphinx-for-chinaese、Sphinx+Scws的区别
2016/12/15 PHP
Thinkphp框架使用list_to_tree 实现无限级分类列出所有节点示例
2020/04/04 PHP
JavaScript面向对象程序设计三 原型模式(上)
2011/12/21 Javascript
Javascript处理DOM元素事件实现代码
2012/05/23 Javascript
JavaScript模板引擎用法实例
2015/07/10 Javascript
九种原生js动画效果
2015/11/11 Javascript
js实现页面跳转的五种方法推荐
2016/03/10 Javascript
基于Bootstrap的UI扩展 StyleBootstrap
2016/06/17 Javascript
jQuery ajax MD5实现用户注册即时验证功能
2016/10/11 Javascript
JS定时检测任务任务完成后执行下一步的解决办法
2016/12/22 Javascript
JavaScript Date 知识浅析
2017/01/29 Javascript
提高Web性能的前端优化技巧总结
2017/02/27 Javascript
js实现常见的工具条效果
2017/03/02 Javascript
vue中实现methods一个方法调用另外一个方法
2018/02/08 Javascript
JS点击动态添加标签、删除指定标签的代码
2018/04/18 Javascript
jQuery使用动画队列自定义动画操作示例
2018/06/16 jQuery
jQuery+css last-child实现选择最后一个子元素操作示例
2018/12/10 jQuery
vue使用recorder.js实现录音功能
2019/11/22 Javascript
Python strip lstrip rstrip使用方法
2008/09/06 Python
一些常用的Python爬虫技巧汇总
2016/09/28 Python
Python中 Lambda表达式全面解析
2016/11/28 Python
Python3中urlencode和urldecode的用法详解
2019/07/23 Python
CSS3径向渐变之大鱼吃小鱼之孤单的大鱼
2016/04/26 HTML / CSS
canvas粒子动画背景的实现示例
2018/09/03 HTML / CSS
HTML5语义化元素你真的用对了吗
2019/08/22 HTML / CSS
英国家庭和商业健身器材购物网站:Fitness Options
2018/07/05 全球购物
英国旅行箱包和行李箱购物网站:Travel Luggage & Cabin Bags
2019/08/26 全球购物
MediaMarkt比利时:欧洲最大电器连锁店
2020/12/21 全球购物
会计找工作求职信范文
2013/12/09 职场文书
医生爱岗敬业演讲稿
2014/08/26 职场文书
暑期学习心得体会
2014/09/02 职场文书
惊天动地观后感
2015/06/10 职场文书
教师培训简讯
2015/07/20 职场文书
公司新员工欢迎词
2015/09/30 职场文书