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 相关文章推荐
基于Jquery实现表格动态分页实现代码
Jun 21 Javascript
关于锚点跳转及jQuery下相关操作与插件
Oct 01 Javascript
jquery实现文字由下到上循环滚动的实例代码
Aug 09 Javascript
Jquery利用mouseenter和mouseleave实现鼠标经过弹出层且可以点击
Feb 12 Javascript
60个很实用的jQuery代码开发技巧收集
Dec 15 Javascript
JavaScript中连接操作Oracle数据库实例
Apr 02 Javascript
jquery实现的美女拼图游戏实例
May 04 Javascript
jQuery往textarea中光标所在位置插入文本的方法
Jun 26 Javascript
js中利用cookie实现记住密码功能
Aug 20 Javascript
JavaScript的继承实现小结
May 07 Javascript
jQuery实现使用sort方法对json数据排序的方法
Apr 17 jQuery
layui 地区三级联动 form select 渲染的实例
Sep 27 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编程中八种常见的文件操作方式
2006/11/19 PHP
php生成百度sitemap站点地图类函数实例
2014/10/17 PHP
PHP简单创建压缩图的方法
2016/08/24 PHP
jQueryUI的Dialog的简单封装
2010/06/07 Javascript
XMLHTTPRequest的属性和方法简介
2010/11/23 Javascript
jquery对元素拖动排序示例
2014/01/16 Javascript
输入框过滤非数字的js代码
2014/09/18 Javascript
js实现window.open不被拦截的解决方法汇总
2014/10/30 Javascript
JavaScript中的console.dir()函数介绍
2014/12/29 Javascript
实例讲解js验证表单项是否为空的方法
2016/01/09 Javascript
jQuery实现简单隔行变色的方法
2016/02/20 Javascript
如何使用Bootstrap的modal组件自定义alert,confirm和modal对话框
2016/03/01 Javascript
nodejs进阶(6)—连接MySQL数据库示例
2017/01/07 NodeJs
element-ui中的select下拉列表设置默认值方法
2018/08/24 Javascript
[02:47]2018年度DOTA2最佳辅助位选手4号位-完美盛典
2018/12/17 DOTA
python使用SMTP发送qq或sina邮件
2017/10/21 Python
Python获取网段内ping通IP的方法
2019/01/31 Python
详解Python sys.argv使用方法
2019/05/10 Python
Django中使用session保持用户登陆连接的例子
2019/08/06 Python
python GUI库图形界面开发之PyQt5信号与槽机制、自定义信号基础介绍
2020/02/25 Python
jenkins+python自动化测试持续集成教程
2020/05/12 Python
查看keras的默认backend实现方式
2020/06/19 Python
台湾租车首选品牌:IWS艾维士租车
2019/05/03 全球购物
美国最大的户外装备和服装购物网站:Backcountry
2019/10/15 全球购物
某公司的.net工程师面试题笔试题
2013/11/22 面试题
环境科学专业个人求职信
2013/09/26 职场文书
水务局局长岗位职责
2013/11/28 职场文书
参观考察邀请函范文
2014/01/29 职场文书
美术教师自我鉴定
2014/02/12 职场文书
实习报告评语
2014/04/26 职场文书
和谐家庭演讲稿
2014/05/24 职场文书
法制宣传标语集锦
2014/06/25 职场文书
长城的导游词
2015/01/30 职场文书
从贫穷到富有,是知识技能和学习力的差别
2019/08/20 职场文书
Pytorch中的学习率衰减及其用法详解
2021/06/05 Python
Go gorilla/sessions库安装使用
2022/08/14 Golang