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多线程的实现方法
May 08 Javascript
国外Lightbox v2.03.3 最新版 下载
Oct 17 Javascript
jQuery-mobile事件监听与用法详解
Nov 23 Javascript
利用VUE框架,实现列表分页功能示例代码
Jan 12 Javascript
AngularJs点击状态值改变背景色的实例
Dec 18 Javascript
浅谈webpack 自动刷新与解析
Apr 09 Javascript
layDate插件设置开始和结束时间
Nov 15 Javascript
js实现下拉框二级联动
Dec 04 Javascript
浅谈vue-router路由切换 组件重用挖下的坑
Nov 01 Javascript
微信小程序实现音频文件播放进度的实例代码
Mar 02 Javascript
原生js实现拖拽移动与缩放效果
Aug 24 Javascript
vue中v-model对select的绑定操作
Aug 31 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字符串比较函数strcmp()和strcasecmp()使用总结
2014/11/19 PHP
PHP-FPM实现性能优化
2016/03/31 PHP
php并发加锁问题分析与设计代码实例讲解
2021/02/26 PHP
PHP中SESSION过期设置
2021/03/09 PHP
日期函数扩展类Ver0.1.1
2006/09/07 Javascript
window.onbeforeunload方法在IE下无法正常工作的解决办法
2010/01/23 Javascript
jQuery中对节点进行操作的相关介绍
2013/04/16 Javascript
JavaScript中最简洁的编码html字符串的方法
2014/10/11 Javascript
js style动态设置table高度
2014/10/21 Javascript
微信WeixinJSBridge API使用实例
2015/05/25 Javascript
详解JavaScript中Date.UTC()方法的使用
2015/06/12 Javascript
jQuery实现定时读取分析xml文件的方法
2015/07/16 Javascript
jQuery 生成svg矢量二维码
2016/08/09 Javascript
easyui 中的datagrid跨页勾选问题的实现方法
2017/01/18 Javascript
JavaScript实现审核流程状态的动态显示进度条
2017/03/15 Javascript
EasyUI的TreeGrid的过滤功能的解决思路
2017/08/08 Javascript
EasyUI在Panel上动态添加LinkButton按钮
2017/08/11 Javascript
360提示[高危]使用存在漏洞的JQuery版本的解决方法
2017/10/27 jQuery
vue-cli脚手架的安装教程图解
2018/09/02 Javascript
说说如何在Vue.js中实现数字输入组件的方法
2019/01/08 Javascript
Node.js实现简单的爬取的示例代码
2019/06/25 Javascript
Angular value与ngValue区别详解
2019/11/27 Javascript
JQuery获得内容和属性方法解析
2020/05/30 jQuery
vue-router 控制路由权限的实现
2020/09/24 Javascript
[52:27]2018DOTA2亚洲邀请赛 3.31 小组赛B组 paiN vs Secret
2018/04/01 DOTA
python获取各操作系统硬件信息的方法
2015/06/03 Python
Python实现鼠标自动在屏幕上随机移动功能
2020/03/14 Python
canvas学习总结三之绘制路径-线段
2019/01/31 HTML / CSS
世界上第一个创建了罩杯系统的美国内衣品牌:Maidenform
2019/03/23 全球购物
毕业生教师求职信
2013/10/20 职场文书
2014乡党委副书记党建工作汇报材料
2014/11/02 职场文书
2014年专项整治工作总结
2014/11/17 职场文书
员工辞职信怎么写
2015/02/27 职场文书
小学二年级语文教学反思
2016/03/03 职场文书
关于公司年会的开幕词
2016/03/04 职场文书
创业计划书之花店
2019/09/20 职场文书