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 相关文章推荐
sina的lightbox效果。
Jan 09 Javascript
学习ExtJS form布局
Oct 08 Javascript
javascript 同时在IE和FireFox获取KeyCode的代码
Feb 07 Javascript
js从Cookies里面取值的简单实现
Jun 30 Javascript
设计模式中的facade外观模式在JavaScript开发中的运用
May 18 Javascript
jQuery实现自动输入email、时间和域名的方法
Aug 24 Javascript
浅谈jquery中next与siblings的区别
Oct 27 Javascript
JS开发中百度地图+城市联动实现实时触发查询地址功能
Apr 13 Javascript
jQuery实现的简单手风琴效果示例
Aug 29 jQuery
让 babel webpack vue 配置文件支持智能提示的方法
Jun 22 Javascript
js利用iframe实现选项卡效果
Aug 09 Javascript
使用vue引入maptalks地图及聚合效果的实现
Aug 10 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+oracle 分页类
2006/10/09 PHP
php全排列递归算法代码
2012/10/09 PHP
Zend Framework入门应用实例详解
2016/12/11 PHP
php+redis实现注册、删除、编辑、分页、登录、关注等功能示例
2017/02/15 PHP
[原创]用javascript实现检测指定目录是否存在的方法
2008/01/12 Javascript
jQuery live( type, fn ) 委派事件实现
2009/10/11 Javascript
基于jquery的给文章加入关键字链接
2010/10/26 Javascript
精心挑选的15款优秀jQuery 本特效插件和教程
2012/08/06 Javascript
一个JavaScript变量声明的知识点
2013/10/28 Javascript
jquery实现界面无刷新加载登陆注册
2016/07/30 Javascript
原生JS实现-星级评分系统的简单实例
2016/08/21 Javascript
domReady的实现案例
2016/11/23 Javascript
百度地图API之百度地图退拽标记点获取经纬度的实现代码
2017/01/12 Javascript
JavaScript表单验证的两种实现方法
2017/02/11 Javascript
使用 Vue.js 仿百度搜索框的实例代码
2017/05/09 Javascript
使用jQuery实现鼠标点击左右按钮滑动切换
2017/08/04 jQuery
jQuery Datatable 多个查询条件自定义提交事件(推荐)
2017/08/24 jQuery
Angular客户端请求Rest服务跨域问题的解决方法
2017/09/19 Javascript
web前端页面生成exe可执行文件的方法
2018/02/08 Javascript
vue组件实现可搜索下拉框扩展
2020/10/23 Javascript
微信小程序实现图片上传
2019/05/23 Javascript
vue-router的钩子函数用法实例分析
2019/10/26 Javascript
js实现列表向上无限滚动
2020/01/13 Javascript
jquery实现拖拽小方块效果
2020/12/10 jQuery
python中利用队列asyncio.Queue进行通讯详解
2017/09/10 Python
python中的字典操作及字典函数
2018/01/03 Python
python3+PyQt5实现自定义流体混合窗口部件
2018/04/24 Python
Python读写docx文件的方法
2018/05/08 Python
python3使用matplotlib绘制散点图
2019/03/19 Python
python实现动态创建类的方法分析
2019/06/25 Python
Python实现动态循环输出文字功能
2020/05/07 Python
keras中模型训练class_weight,sample_weight区别说明
2020/05/23 Python
python 如何上传包到pypi
2020/12/24 Python
Dockers美国官方网站:卡其裤、男士服装、鞋及配件
2016/11/22 全球购物
2019年关于小学生课外阅读情况的分析报告
2019/12/02 职场文书
详解Redis主从复制实践
2021/05/19 Redis