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 相关文章推荐
网页自动刷新,不产生嗒嗒声的一个解决方法
Mar 27 Javascript
基于jQuery架构javascript基础体系
Jan 01 Javascript
jquery load()在firefox(火狐)下显示不正常的解决方法
Apr 05 Javascript
javascript开发随笔一 preventDefault的必要
Nov 25 Javascript
JavaScript字符串String和Array操作的有趣方法
Dec 18 Javascript
利用jQuery实现可输入搜索文字的下拉框
Oct 23 Javascript
Vue.js教程之axios与网络传输的学习实践
Apr 29 Javascript
微信小程序radio组件使用详解
Jan 31 Javascript
vue 实现的树形菜的实例代码
Mar 19 Javascript
vue 之 css module的使用方法
Dec 04 Javascript
vue cli3适配所有端方案的实现
Apr 13 Javascript
JS 数组和对象的深拷贝操作示例
Jun 06 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
Views rows style模板重写代码
2011/05/16 PHP
php 启动时报错的简单解决方法
2014/01/27 PHP
PHP正则表达式 /i, /is, /s, /isU等介绍
2014/10/23 PHP
初识laravel5
2015/03/02 PHP
php按字符无乱码截取中文的方法
2015/03/27 PHP
PHP Laravel中的Trait使用方法
2019/01/20 PHP
浅谈laravel框架与thinkPHP框架的区别
2019/10/23 PHP
常用js脚本
2006/12/03 Javascript
JavaScript 操作键盘的Enter事件(键盘任何事件),兼容多浏览器
2010/10/11 Javascript
IE6中链接A的href为javascript协议时不在当前页面跳转
2014/06/05 Javascript
jQuery获取动态生成的元素示例
2014/06/15 Javascript
js中键盘事件实例简析
2015/01/10 Javascript
JavaScript在网页中画圆的函数arc使用方法
2015/11/13 Javascript
JavaScript中splice与slice的区别
2017/05/09 Javascript
pace.js和NProgress.js两个加载进度插件的一点小总结
2018/01/31 Javascript
原生js实现省市区三级联动代码分享
2018/02/12 Javascript
简单介绍react redux的中间件的使用
2018/04/06 Javascript
[33:39]DOTA2上海特级锦标赛C组小组赛#2 LGD VS Newbee第二局
2016/02/27 DOTA
[54:26]完美世界DOTA2联赛PWL S3 Forest vs Rebirth 第一场 12.10
2020/12/12 DOTA
python获取当前时间对应unix时间戳的方法
2015/05/15 Python
Python  pip安装lxml出错的问题解决办法
2017/02/10 Python
python使用mysql数据库示例代码
2017/05/21 Python
Python字符串格式化%s%d%f详解
2018/02/02 Python
python3.8 微信发送服务器监控报警消息代码实现
2019/11/05 Python
对tensorflow中的strides参数使用详解
2020/01/04 Python
opencv 查找连通区域 最大面积实例
2020/06/04 Python
详解python对象之间的交互
2020/09/29 Python
python 求两个向量的顺时针夹角操作
2021/03/04 Python
公司采购主管岗位职责
2014/06/17 职场文书
党的群众路线对照检查材料
2014/08/27 职场文书
公司法人授权委托书范本
2014/09/12 职场文书
乡镇党员干部群众路线对照检查材料思想汇报
2014/09/28 职场文书
2014年卫生工作总结
2014/11/27 职场文书
关爱留守儿童主题班会
2015/08/13 职场文书
使用 CSS 构建强大且酷炫的粒子动画效果
2022/08/14 HTML / CSS
了解MySQL查询语句执行过程(5大组件)
2022/08/14 MySQL