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 iframe内部出滚动条
Feb 11 Javascript
自己动手制作jquery插件之自动添加删除行的实现
Oct 13 Javascript
Javacript实现颜色梯度变化和渐变的效果代码
May 31 Javascript
js 3种归并操作的实例代码
Oct 30 Javascript
JavaScript实现梯形乘法表的方法
Apr 25 Javascript
jQuery实现dialog设置focus焦点的方法
Jun 10 Javascript
理解javascript封装
Feb 23 Javascript
JS实现两周内自动登录功能
Mar 23 Javascript
vue proxyTable 接口跨域请求调试的示例
Sep 12 Javascript
vue+SSM实现验证码功能
Dec 07 Javascript
使用原生JS实现滚轮翻页效果的示例代码
May 31 Javascript
JavaScript中时间格式化新思路toLocaleString()
Nov 07 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编程过程中需要了解的this,self,parent的区别
2009/12/30 PHP
fleaphp crud操作之find函数的使用方法
2011/04/23 PHP
php5.5中类级别的常量使用介绍
2013/10/02 PHP
php文件服务实现虚拟挂载其他目录示例
2014/04/17 PHP
非常好用的Zend Framework分页类
2014/06/25 PHP
php正则匹配文章中的远程图片地址并下载图片至本地
2015/09/29 PHP
PHP实现GIF图片验证码
2015/11/04 PHP
php 生成签名及验证签名详解
2016/10/26 PHP
JSON 数字排序多字段排序介绍
2013/09/18 Javascript
使用简洁的jQuery方法实现隔行换色功能
2014/01/02 Javascript
JavaScript对象之深度克隆介绍
2014/12/08 Javascript
JavaScript获得url所有参数键值表的方法
2015/03/21 Javascript
用JS生成UUID的方法实例
2016/03/30 Javascript
Bootstrap中data-target 到底是什么
2017/02/14 Javascript
js实现字符全排列算法的简单方法
2017/05/01 Javascript
javascript 中select框触发事件过程的分析
2017/08/01 Javascript
jQuery中过滤器的基本用法示例
2017/10/11 jQuery
利用ES6实现单例模式及其应用详解
2017/12/09 Javascript
取消Bootstrap的dropdown-menu点击默认关闭事件方法
2018/08/10 Javascript
微信接入之获取用户头像的方法步骤
2019/09/23 Javascript
LayUi数据表格自定义赋值方式
2019/10/26 Javascript
vue全局使用axios的操作
2020/09/08 Javascript
[01:06] DOTA2英雄背景故事第三期之秩序法则光之守卫
2020/07/07 DOTA
Python中的模块和包概念介绍
2015/04/13 Python
python使用Flask操作mysql实现登录功能
2018/05/14 Python
eclipse创建python项目步骤详解
2019/05/10 Python
python的range和linspace使用详解
2019/11/27 Python
python调用摄像头的示例代码
2020/09/28 Python
Canvas高级路径操作之拖拽对象的实现
2019/08/05 HTML / CSS
美国葡萄酒网上商店:Martha Stewart Wine Co.
2019/03/17 全球购物
全球领先的全景影像品牌:Insta360
2019/08/21 全球购物
学习经验演讲稿
2014/05/10 职场文书
文明演讲稿范文
2014/05/12 职场文书
党员群众路线学习心得体会
2014/11/04 职场文书
挂职锻炼个人总结
2015/03/05 职场文书
学习党章心得体会2016
2016/01/15 职场文书