JS闭包原理与应用经典示例


Posted in Javascript onDecember 20, 2018

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

一、先来看一个例子:

function foo() {
   var a = 10;
   function bar() {
    a *= 2;
    return a;
   }
   return bar;
}
var baz = foo(); // baz is now a reference to function bar.
console.log(baz()); // returns 20.
console.log(baz()); // returns 40.
console.log(baz()); // returns 80.
var blat = foo(); // blat is another reference to bar.
console.log(blat()); // returns 20, because a new copy of a is being used.

这里使用在线HTML/CSS/JavaScript代码运行工具:http://tools.3water.com/code/HtmlJsRun测试上述代码,可得到如下运行结果:

JS闭包原理与应用经典示例

一直以来,我都是以为只有用匿名函数才能算是闭包,但是其实不一定要用匿名函数的,就是一般的函数就可以,前提是它得被包含在另一个函数中。

在foo返回后,它的作用域被保存下来了,但只有它返回的的那个函数能够访问这个作用域。在前面的示例中,baz和balt各有各的作用域及a的一个副本,而且只有他们自己能对其进行修改。

其实就是说我们对foo函数的引用的调用并不会对其他引用有任何影响。

二、封装和隐藏信息

看了上面的例子,我们可以考虑采用匿名函数来进行封装和隐藏私有变量。

var Book = function(newIsbn, newTitle, newAuthor) { // implements Publication
 // Private attributes.
 var isbn, title, author;
 // Private method.
 function checkIsbn(isbn) {
  //...
  return true;
 }
 // Privileged methods.
 this.getIsbn = function() {
  return isbn;
 };
 this.setIsbn = function(newIsbn) {
  if(!checkIsbn(newIsbn)) throw new Error('Book: Invalid ISBN.');
  isbn = newIsbn;
 };
 this.getTitle = function() {
  return title;
 };
 this.setTitle = function(newTitle) {
  title = newTitle || 'No title specified';
 };
 this.getAuthor = function() {
  return author;
 };
 this.setAuthor = function(newAuthor) {
  author = newAuthor || 'No author specified';
 };
 // Constructor code.
 this.setIsbn(newIsbn);
 this.setTitle(newTitle);
 this.setAuthor(newAuthor);
};
// Public, non-privileged methods.
Book.prototype = {
 display: function() {
  //...
 }
};
var mybook=new Book("myisbtn","mytittle","myauthor");
console.log(mybook.getAuthor());

使用在线HTML/CSS/JavaScript代码运行工具:http://tools.3water.com/code/HtmlJsRun测试上述代码,可得到如下运行结果:

JS闭包原理与应用经典示例

我们通过在构造器中用var声明了这些变量和checkIsbn函数,因此他们就变成了私有的属性。需要访问这些变量和函数的方法只需要在Book中声明即可。这些方法也被陈伟特权方法。而任何不需要访问私有属性的方法都要在Book.prototype中声明。例如display。但这里也存在个问题:就是每生成一个新的对象实例都将为每一个私有方法和特权方法生成一个新的副本。这会比其他做法耗费更多内存,因此只宜用在真正需要私有成员的场合。另外,这种模式也不适合派生子类,因为派生的子类并不能访问超类的任何私有属性和方法。故在JavaScript中用闭包实现私有成员导致派生问题被称为“继承破坏封装”。

三、改进

这里与上一种大体类似,但是也有一些重要的区别。这里私有成员和特权成员仍被声明在构造器中,但是构造器已经变成一个内嵌函数了,并且被作为包含它的函数的返回值赋给变量Book.这就是创建了一个闭包,你可以把静态的私有成员函数声明在里面。

checkIsbn函数被设置为静态方法,是因为没必要为每个实例都生成这个方法的一个副本。此外还有静态属性numBooks限制了构造器总的调用次数

var Book = (function() {
 // Private static attributes.
 var numOfBooks = 0;
 // Private static method.
 function checkIsbn(isbn) {
  // ...
  return true;
 }
 // Return the constructor.
 return function(newIsbn, newTitle, newAuthor) { // implements Publication
  // Private attributes.
  var isbn, title, author;
  // Privileged methods.
  this.getIsbn = function() {
   return isbn;
  };
  this.setIsbn = function(newIsbn) {
   if(!checkIsbn(newIsbn)) throw new Error('Book: Invalid ISBN.');
   isbn = newIsbn;
  };
  this.getTitle = function() {
   return title;
  };
  this.setTitle = function(newTitle) {
   title = newTitle || 'No title specified';
  };
  this.getAuthor = function() {
   return author;
  };
  this.setAuthor = function(newAuthor) {
   author = newAuthor || 'No author specified';
  };
  // Constructor code.
  numOfBooks++; // Keep track of how many Books have been instantiated
         // with the private static attribute.
  if(numOfBooks > 1) throw new Error('Book: Only 1 instances of Book can be '
    + 'created.');
  this.setIsbn(newIsbn);
  this.setTitle(newTitle);
  this.setAuthor(newAuthor);
 }
})();
// Public static method.
Book.convertToTitleCase = function(inputString) {
 //...
 console.log("convertToTitleCase");
};
// Public, non-privileged methods.
Book.prototype = {
 display: function() {
  //...
  console.log("display");
 }
};
var mybook=new Book("myisbtn","mytittle","myauthor");
console.log(mybook.getAuthor());  //myauthor
mybook.display();          //display
//mybook.convertToTitleCase();   //mybook.convertToTitleCase is not a function
var mybook2= new Book("my2","tittle2","myauthor2");
console.log(mybook2.getAuthor());  //Only 1 instances of Book can be created.

使用在线HTML/CSS/JavaScript代码运行工具:http://tools.3water.com/code/HtmlJsRun测试上述代码,可得到如下运行结果:

JS闭包原理与应用经典示例

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

Javascript 相关文章推荐
JavaScript学习点滴 call、apply的区别
Oct 22 Javascript
javascript表单验证和Window详解
Dec 11 Javascript
微信小程序 底部导航栏目开发资料
Dec 05 Javascript
js闭包用法实例详解
Dec 13 Javascript
input输入密码变黑点密文的实现方法
Jan 09 Javascript
原生js实现手风琴功能(支持横纵向调用)
Jan 13 Javascript
vue事件修饰符和按键修饰符用法总结
Jul 25 Javascript
vue实现自定义日期组件功能的实例代码
Nov 06 Javascript
IE8中jQuery.load()加载页面不显示的原因
Nov 15 jQuery
浅探express路由和中间件的实现
Sep 30 Javascript
详解关闭令人抓狂的ESlint 语法检测配置方法
Oct 28 Javascript
Moment的feature导致线上bug解决分析
Sep 23 Javascript
Mint UI组件库CheckList使用及踩坑总结
Dec 20 #Javascript
从零开始在NPM上发布一个Vue组件的方法步骤
Dec 20 #Javascript
微信小程序实现swiper切换卡内嵌滚动条不显示的方法示例
Dec 20 #Javascript
微信小程序实现的点击按钮 弹出底部上拉菜单功能示例
Dec 20 #Javascript
vue+Vue Router多级侧导航切换路由(页面)的实现代码
Dec 20 #Javascript
微信小程序module.exports模块化操作实例浅析
Dec 20 #Javascript
JavaScript类的继承操作实例总结
Dec 20 #Javascript
You might like
php小技巧 把数组的键和值交换形成了新的数组,查找值取得键
2011/06/02 PHP
第三章 php操作符与控制结构代码
2011/12/30 PHP
eaglephp使用微信api接口开发微信框架
2014/01/09 PHP
php获取四位字母和数字的随机数的实现方法
2015/01/09 PHP
YII动态模型(动态表名)支持分析
2016/03/29 PHP
PHP如何获取当前主机、域名、网址、路径、端口等参数
2017/06/09 PHP
PHP7下协程的实现方法详解
2017/12/17 PHP
PHP实现的一致性Hash算法详解【分布式算法】
2018/03/31 PHP
国外的为初学者写的JavaScript教程
2008/06/09 Javascript
使用angular写一个hello world
2015/01/23 Javascript
再次谈论React.js实现原生js拖拽效果引起的一系列问题
2016/04/03 Javascript
微信小程序 chooseImage选择图片或者拍照
2017/04/07 Javascript
基于vue+ bootstrap实现图片上传图片展示功能
2017/05/17 Javascript
Vue filters过滤器的使用方法
2017/07/14 Javascript
vue 组件中添加样式不生效的解决方法
2018/07/06 Javascript
微信小程序自定义组件之可清除的input组件
2018/07/17 Javascript
在 Vue.js中优雅地使用全局事件的方法
2019/02/01 Javascript
vue将data恢复到初始状态 && 重新渲染组件实例
2020/09/04 Javascript
[03:57]DOTA2英雄梦之声_第03期_幻影刺客
2014/06/21 DOTA
[03:26]《DAC最前线》之EG经理自述DOTA2经历
2015/02/02 DOTA
[00:36]DOTA2上海特级锦标赛 Archon战队宣传片
2016/03/04 DOTA
Python实例分享:快速查找出被挂马的文件
2014/06/08 Python
python多进程共享变量
2016/04/06 Python
[原创]Python入门教程2. 字符串基本操作【运算、格式化输出、常用函数】
2018/10/29 Python
启动Atom并运行python文件的步骤
2018/11/09 Python
Python中join()函数多种操作代码实例
2020/01/13 Python
深入浅析Python 函数注解与匿名函数
2020/02/24 Python
python GUI库图形界面开发之PyQt5菜单栏控件QMenuBar的详细使用方法与实例
2020/02/28 Python
使用Python内置模块与函数进行不同进制的数的转换
2020/04/26 Python
Python日志:自定义输出字段 json格式输出方式
2020/04/27 Python
网络艺术零售业的先驱者:artrepublic
2017/09/26 全球购物
保卫科工作岗位职责
2014/03/01 职场文书
大学优秀班集体申报材料
2014/05/23 职场文书
餐厅周年庆活动方案
2014/08/25 职场文书
学校班子个人对照检查材料思想汇报
2014/09/27 职场文书
选购到合适的激光打印机
2022/04/21 数码科技