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 相关文章推荐
js 变量类型转换常用函数与代码[比较全]
Dec 01 Javascript
15条JavaScript最佳实践小结
Aug 09 Javascript
js字符串日期yyyy-MM-dd转化为date示例代码
Mar 06 Javascript
jQuery多个input求和的实现方法
Feb 12 Javascript
在WordPress中加入Google搜索功能的简单步骤讲解
Jan 04 Javascript
浅析JS获取url中的参数实例代码
Jun 14 Javascript
EasyUI 中combotree 默认不能选择父节点的实现方法
Nov 07 Javascript
JavaScript实现按键精灵的原理分析
Feb 21 Javascript
boostrap模态框二次弹出清空原有内容的方法
Aug 10 Javascript
vue1.0和vue2.0的watch监听事件写法详解
Sep 11 Javascript
微信小程序按钮点击跳转页面详解
May 06 Javascript
Vue仿Bibibili首页的问题
Jan 21 Vue.js
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函数strip_tags的一个bug浅析
2014/05/22 PHP
php常用的url处理函数总结
2014/11/19 PHP
thinkphp命名空间用法实例详解
2015/12/30 PHP
javascript Keycode对照表
2009/10/24 Javascript
js汉字排序问题 支持中英文混排,兼容各浏览器,包括CHROME
2011/12/20 Javascript
使用Math.floor与Math.random取随机整数的方法详解
2013/05/07 Javascript
JSP跨iframe如何传递参数实现代码
2013/09/21 Javascript
完美兼容各大浏览器获取HTTP_REFERER方法总结
2014/06/24 Javascript
jQuery获取选中内容及设置元素属性的方法
2014/07/09 Javascript
JavaScript使用replace函数替换字符串的方法
2015/04/06 Javascript
javascript实现淘宝幻灯片广告展示效果
2015/04/27 Javascript
JavaScript中的Math.atan2()方法使用详解
2015/06/15 Javascript
js实现控制textarea输入字符串的个数,鼠标按下抬起判断输入字符数
2016/10/25 Javascript
Vue.js 2.x之组件的定义和注册图文详解
2018/06/19 Javascript
详解Vue+axios+Node+express实现文件上传(用户头像上传)
2018/08/10 Javascript
微信小程序自定义导航栏
2018/12/31 Javascript
详解如何给React-Router添加路由页面切换时的过渡动画
2019/04/25 Javascript
关于Vue源码vm.$watch()内部原理详解
2019/04/26 Javascript
解决父组件将子组件作为弹窗调用只执行一次created的问题
2020/07/24 Javascript
js 将多个对象合并成一个对象 assign方法的实现
2020/09/24 Javascript
python中装饰器级连的使用方法示例
2017/09/29 Python
50行Python代码实现人脸检测功能
2018/01/23 Python
python游戏开发之视频转彩色字符动画
2019/04/26 Python
Python基于jieba, wordcloud库生成中文词云
2020/05/13 Python
Python的控制结构之For、While、If循环问题
2020/06/30 Python
关于Python3爬虫利器Appium的安装步骤
2020/07/29 Python
德国童装购物网站:NICKI´S.com
2018/04/20 全球购物
中东最大的在线宠物店:Dubai Pet Food
2020/06/11 全球购物
"引用"与指针的区别是什么
2016/09/07 面试题
《月光启蒙》教学反思
2014/03/01 职场文书
《美丽的丹顶鹤》教学反思
2014/04/22 职场文书
个人自荐书范文
2015/03/09 职场文书
杨善洲电影观后感
2015/06/04 职场文书
2016年教师反腐倡廉心得体会
2016/01/13 职场文书
python基础之类方法和静态方法
2021/10/24 Python
Nginx实现负载均衡的项目实践
2022/03/18 Servers