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
用JS实现3D球状标签云示例代码
Dec 01 Javascript
兼容Firefox的Javascript XSLT 处理XML文件
Dec 31 Javascript
ExpressJS入门实例
Jan 14 Javascript
js判断文本框剩余可输入字数的方法
Feb 04 Javascript
jQuery解析XML文件同时动态增加js文件的方法
Jun 01 Javascript
JS仿hao123导航页面图片轮播效果
Sep 01 Javascript
一个非常好用的文字滚动的案例,鼠标悬浮可暂停[两种方案任选]
Dec 01 Javascript
浅谈Node异步编程的机制
Oct 18 Javascript
浅析Vue自定义组件的v-model
Nov 26 Javascript
js实现图片区域可点击大小随意改变(适用移动端)代码实例
Sep 11 Javascript
vue项目实现图片上传功能
Dec 23 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
ThinkPHP与PHPExcel冲突解决方法
2011/08/08 PHP
PHP中对缓冲区的控制实现代码
2013/09/29 PHP
PHP+fiddler抓包采集微信文章阅读数点赞数的思路详解
2019/12/20 PHP
原型方法的不同写法居然会影响调试的解决方法
2007/03/08 Javascript
jquery模拟按下回车实现代码
2011/09/20 Javascript
javascript setinterval 的正确语法如何书写
2014/06/17 Javascript
js实现按钮控制图片360度翻转特效的方法
2015/02/17 Javascript
jQuery实现的fixedMenu下拉菜单效果代码
2015/08/24 Javascript
基于jQuery实现选取月份插件附源码下载
2015/12/28 Javascript
详解javascript高级定时器
2015/12/31 Javascript
用JS写的一个Ajax库(实例代码)
2016/08/06 Javascript
vue中的非父子间的通讯问题简单的实例代码
2017/07/19 Javascript
AngularJS实现的select二级联动下拉菜单功能示例
2017/10/25 Javascript
Angular开发实践之服务端渲染
2018/03/29 Javascript
JavaScript设计模式之观察者模式(发布订阅模式)原理与实现方法示例
2018/07/27 Javascript
基于layui table返回的值的多级嵌套的解决方法
2019/09/19 Javascript
python使用calendar输出指定年份全年日历的方法
2015/04/04 Python
详解python项目实战:模拟登陆CSDN
2019/04/04 Python
pytorch ImageFolder的覆写实例
2020/02/20 Python
python函数enumerate,operator和Counter使用技巧实例小结
2020/02/22 Python
python数据库操作mysql:pymysql、sqlalchemy常见用法详解
2020/03/30 Python
python读取hdfs并返回dataframe教程
2020/06/05 Python
Python进行统计建模
2020/08/10 Python
使用phonegap检测网络状态的方法
2017/03/30 HTML / CSS
优衣库美国官网:UNIQLO美国
2018/04/14 全球购物
塑料制成的可水洗的编织平底鞋和鞋子:Rothy’s
2018/09/16 全球购物
Tommy Hilfiger澳洲官网:美国高端休闲领导品牌
2020/12/16 全球购物
Nike俄罗斯官方网站:Nike RU
2021/03/05 全球购物
区域总监的岗位职责
2013/11/21 职场文书
写给女朋友的道歉信
2014/01/12 职场文书
外贸会计专业自荐信
2014/06/22 职场文书
跑出一片天观后感
2015/06/08 职场文书
边城读书笔记
2015/06/29 职场文书
医院保洁员管理制度
2015/08/05 职场文书
如何写好活动总结
2019/06/21 职场文书
Maven学习----Maven安装与环境变量配置教程
2021/06/29 Java/Android