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 浏览器判断 绑定事件 arguments 转换数组 数组遍历
Jul 06 Javascript
判断iframe是否加载完成的完美方法
Jan 07 Javascript
js对象数组按属性快速排序
Jan 31 Javascript
JQuery获取各种宽度、高度(format函数)实例
Mar 04 Javascript
浅析JavaScript事件和方法
Feb 28 Javascript
javascript每日必学之继承
Feb 23 Javascript
JavaScript实战(原生range和自定义特效)简单实例
Aug 21 Javascript
微信小程序 this和that详解及简单实例
Feb 13 Javascript
分享Bootstrap简单表格、表单、登录页面
Aug 04 Javascript
vue cli 全面解析
Feb 28 Javascript
vue使用监听实现全选反选功能
Jul 06 Javascript
vue实现简单加法计算器
Oct 22 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 异常处理实现代码
2009/03/10 PHP
PHP实现变色验证码实例
2014/01/06 PHP
PHP中调用C/C++制作的动态链接库的教程
2016/03/10 PHP
php+webSoket实现聊天室示例代码(附源码)
2017/02/17 PHP
php简单随机字符串生成方法示例
2017/04/19 PHP
PHP将数据导出Excel表中的实例(投机型)
2017/07/31 PHP
再谈javascript 动态添加样式规则 W3C校检
2009/12/25 Javascript
IE6 弹出Iframe层中的文本框“经常”无法获得输入焦点
2009/12/27 Javascript
Extjs学习笔记之三 extjs form更多的表单项
2010/01/07 Javascript
jquery实现的美女拼图游戏实例
2015/05/04 Javascript
innerHTML中标签可以换行的方法汇总
2015/08/14 Javascript
JS实现的3D拖拽翻页效果代码
2015/10/31 Javascript
基于Vue实现tab栏切换内容不断实时刷新数据功能
2017/04/13 Javascript
基于JavaScript实现的插入排序算法分析
2017/04/14 Javascript
ionic+AngularJs实现获取验证码倒计时按钮
2017/04/22 Javascript
BootStrap Table实现server分页序号连续显示功能(当前页从上一页的结束序号开始)
2017/09/12 Javascript
vue组件父与子通信详解(一)
2017/11/07 Javascript
用 Vue.js 递归组件实现可折叠的树形菜单(demo)
2017/12/25 Javascript
简易Vue评论框架的实现(父组件的实现)
2018/01/08 Javascript
详解react、redux、react-redux之间的关系
2018/04/11 Javascript
基于iview的router常用控制方式
2019/05/30 Javascript
vue中利用three.js实现全景图的完整示例
2020/12/07 Vue.js
在python中按照特定顺序访问字典的方法详解
2018/12/14 Python
Python 装饰器原理、定义与用法详解
2019/12/07 Python
matplotlib运行时配置(Runtime Configuration,rc)参数rcParams解析
2021/01/05 Python
T3官网:头发造型工具
2019/12/26 全球购物
建筑设计所实习生自我鉴定
2013/09/25 职场文书
班组长岗位职责范本
2014/01/05 职场文书
竞争上岗演讲稿
2014/01/05 职场文书
志愿者活动总结范文
2014/04/26 职场文书
电子商务系毕业生自荐信
2014/05/29 职场文书
机关作风整顿个人剖析材料
2014/10/06 职场文书
写给妈妈的感谢信
2015/01/22 职场文书
办公用品质量保证书
2015/05/11 职场文书
个人工作失误的保证书怎么写?
2019/06/21 职场文书
PHP中国际化的字符串排序和比较对象详解
2021/08/23 PHP