1. 封装与 信息隐藏之间的关系

实质是同一个概念的两种表达,信息隐藏式目的,二封装是借以达到目的的技术方法。封装是对象内部的数据表现形式和实现细节,要想访问封装过额对象中的数据,只有使用自己定义的操作方法。通过封装可以强制实施信息的隐藏。

2. 重新认识创建对象的基本方式

01.用一个函数来做构造器

var Book = function (isbn, title, author){
if(isbn == undefined) throw new Error ('构造器需要一个 isbn');
this.isbn = isbn;
this.title = title || 'No title specified';
this.author = author || 'No author specified';
} Book.prototype.display = function() {
// 你的代码
}

在构造器中,如果没有提供isbn ,将会抛出一个错误。title和author参数都是可选的,所以要准备默认值以防止他们未被提供。

似乎这个类符合我们的需要,但是问题是我们无法检验isbn的数据完整性,不完整的数据可能会导致我们的程序出错。所以我们对Book类进行了强化,加强了对isbn的检查。

代码如下:

var Book = function(isbn,title,author){
if(!this.checkIsbn(isbn)) throw new Error ('Book: Invalid Isbn');
this.isbn = isbn;
this.title = title || 'No title specified';
this.author = author|| 'No author specified';
} Book.prototype = {
checkIsbn : function(isbn){
if(isbn == undefined || typeof isbn != 'String'){
return false;
} isbn = isbn.replace(/-/, ''); //去掉虚线 if(isbn.length != && isbn.length != ) {
return false;
} var sum = ;
if(isbn.length === ) {
if(!isbn.match(/^\d{}/)){//保证一至九 数字
return false;
}
for (var i=;i<;i++){
sum += isbn.charAt(i)*(-i);
}
var checksum = sum %;
if(checksum ===) checksum = 'X';
if(isbn.charAt() != checksum){
return false;
}
} else {
if(!isbn.match(/^\d{}/)){
return false;
}
for(var i = ;i<;i++){
sum+= isbn.charAt(i)*((i%===)?:);
}
var checksum = sum%;
if(isbn.charAt() != checksum){
return false;
}
}
return true;
}
display: function() {
//你的代码
} }

这段代码 添加了一个checkIsbn方法,用来保障Isbn 是一个具有正确位数和检验的字符串,因为现在该类有了连个方法,所以Book.prototype被设置为一个对象字面量。现在情况有所改善,我们可以在构造器中对数据进行检验。但是别人会将什么样的值直接赋给isbn属性还是没有控制。

这就需要用到,取值器和赋值器

var Book = function(isbn,title,author){
this.setIsbn(isbn);
this.setTitle(title);
this.setAuthor(author);
}; Book.prototype = {
checkIsbn: function(){
//检查所用代码
},
getIsbn: function(){
return this.isbn;
} ,
setIsbn: function(){
if(!this.checkIsbn(isbn)) throw new Error('Book: Invalid ISBN' );
this.isbn = isbn;
},
getTitle: function() {
return this.title;
},
setTitle: function(){
this.title = title||'No title specified'
},
display: function(){
//你的代码
} }

这种写法对数据有一定的保护作用,也非常容易编写,但是属性是公开的,可以直接设置。

3. 在实现私有方法和属性之前 我们必须知道原理: 作用域、嵌套函数、闭包

栗子:

function foo(){
var a=;
function bar(){
a*=;
}
bar();
return a; }

在这个栗子中,a定义在函数foo中,但函数bar可以访问它,因为bar也定义在foo中。bar在执行过程中将a设置为a*=2;当bar 在foo 中被调用时能够访问a,这可以理解,但是如果bar 在foo外部被调用呢?

function foo(){
var a = ;
function bar(){
a*=;
return a;
}
return bar; } var baz = foo(); // baz 是bar 的一个引用
baz(); //返回20
baz(); //返回40
baz(); //返回80 var test = foo(); // 这是另外一个引用
test(); // 返回20 因为是另外一个引用

在这段代码中,所返回的对bar 函数的引用被赋给变量baz。这个函数现在是在foo外部被调用,但依然可以访问a。这是因为javaScript中的作用域是词法性的。 函数是运行在定义他们的作用域中,而不是运行在调用她们的作用域中。只用bar被定义在foo中,就可以访问foo中定义的所有变量,即使foo的执行已经结束;

这就是一个闭包的例子,在foo返回后,它的作用域被保存下来,但只有它返回的那个函数能够访问这个作用域。---》返回一个内嵌函数是创建闭包的常用手段。

那么,问题来了,如何用闭包实现私有成员

借助闭包,我们可以创建只允许特定函数访问的变量,而且这些变量在这些函数的各次调用依然存在。为了创建私有属性,我们需要在构造函数的作用域中定义相关变量。这些变量可以被定义在该作用域中的所欲函数访问,包括特权方法。

var Book = function(newIsbn,newTitle,newAuthor){
var isbn , title, author; //私有属性
function checkIsbn(isbn){ // 私有方法
// 检查isbn的代码
} // 特权方法
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(){
title = newTitle || 'No title specified'
} this.setIsbn(newIsbn);
this.setTitle(newTitle);
this.setAuthor(newAuthor); } Book.prototype = {
display: function(){
// 要写的代码
}
}

这与之前的有什么不一样呢? 在其他的例子中,我们创建和引用对象的属性是总是要用this关键字。而现在我们用var 生明这些变量。这意味着它们只存在于Book构造器中。checkIsbn函数也是同样声明的,因此成了一个私用方法;

需要访问这些变量和函数的方法 只需声明在Book中即可。被称为 特权方法,因为它们是公用方法,但是却可以访问私用属性和方法。 为了在队形外部能访问这些特权方法,它们前面都加上了this关键字。因为它们定义在Book构造器的作用域中,所以它们可以访问私用属性。

任何不需要直接访问私用属性的方法否可以在Book.prototype中声明。

再看下边的代码:

var Book = (function(){
var numOfbooks = ;
function checkIsbn(isbn){
// 检查代码
}
// 返回一个构造器
retrun function(newIsbn,newTitle,newAuthor){
var isbn ,title, author; this.getIsbn = function(){
return isbn;
}
this.setIsbn = function(newIsbn){
if(!checkIsbn(newIsbn)) throw new Error('');
isbn = newIsbn
}
// 其它get , set 方法类似
numOfbooks++;
if(numOfbooks > ) throw new Error ('book: only 50 instance o f book can be created') this.setIsbn(newIsbn);
this.setTitle(newTitle);
this.setAuthor(newAuthor);
} })() Book.convertToTitleCace = function(inputString){
//......
} Book.prototype = function(){
display:function(){
// ......
}
}

这里的私用成员和特权成员仍然被声明在构造器中,但是构造器却从普通函数变成了一个内嵌函数,并且被作为包含他的函数的返回值赋给变量Book。这就创建了一个闭包。我们可以把静态的私用成员声明在里面。外层函数是一个立即执行函数,返回值是另一个函数,赋值给变量Book ,Book变成了一个构造函数,在实例化时,调用的是内层函数,外层函数只是用来创建一个可以存放静态私用成员的闭包。

ps: 到此为止,我们应该可以基本理解对象的封装 及 创建私有化成员 。

如果觉得文章不错,欢迎。。。你懂得。。。

如何封装JS ----》JS设计模式《------ 封装与信息隐藏的更多相关文章

  1. JS设计模式——3.封装与信息隐藏

    封装.信息隐藏与接口的关系 信息隐藏是目的,封装是手段. 接口提供了一份记载着可供公共访问的方法的契约.它定义了两个对象间可以具有的关系.只要接口不变,这个关系的双方都是可以替换的. 一个理想的软件系 ...

  2. JavaScript设计模式——前奏(封装和信息隐藏)

    前面一篇讲了js设计模式的前奏,包括接口的讲解.. 三:封装和信息隐藏: 信息隐藏用来进行解耦,定义一些私有的数据和方法. 封装是用来实现信息隐藏的技术,通过闭包实现私有数据的定义和使用. 接口在这其 ...

  3. JS组件系列——封装自己的JS组件,你也可以

    前言:之前分享了那么多bootstrap组件的使用经验,这篇博主打算研究下JS组件的扩展和封装,我们来感受下JQuery为我们提供$.Extend的神奇,看看我们怎么自定义自己的组件,比如我们想扩展一 ...

  4. JS组件系列——封装自己的JS组件

    前言:之前分享了那么多bootstrap组件的使用经验,这篇博主打算研究下JS组件的扩展和封装,我们来感受下JQuery为我们提供$.Extend的神奇,看看我们怎么自定义自己的组件,比如我们想扩展一 ...

  5. 【转】第7篇:Xilium CefGlue 关于 CLR Object 与 JS 交互类库封装报告:全自动注册与反射方法分析

    作者: 牛A与牛C之间 时间: 2013-12-12 分类: 技术文章 | 2条评论 | 编辑文章 主页 » 技术文章 » 第7篇:Xilium CefGlue 关于 CLR Object 与 JS ...

  6. 【转】第4篇:Xilium CefGlue 关于 CLR Object 与 JS 交互类库封装报告:委托回调方法分析

    作者: 牛A与牛C之间 时间: 2013-11-18 分类: 技术文章 | 暂无评论 | 编辑文章 主页 » 技术文章 » 第4篇:Xilium CefGlue 关于 CLR Object 与 JS ...

  7. 【转】3篇:Xilium CefGlue 关于 CLR Object 与 JS 交互类库封装报告:官方原生方法分析

    作者: 牛A与牛C之间 时间: 2013-11-17 分类: 技术文章 | 暂无评论 | 编辑文章 主页 » 技术文章 » 第3篇:Xilium CefGlue 关于 CLR Object 与 JS ...

  8. 原生JS面向对象思想封装轮播图组件

    原生JS面向对象思想封装轮播图组件 在前端页面开发过程中,页面中的轮播图特效很常见,因此我就想封装一个自己的原生JS的轮播图组件.有了这个需求就开始着手准备了,代码当然是以简洁为目标,轮播图的各个功能 ...

  9. js创建类(封装)

    js如何创建类(封装)     学过其他面向对象语言的JavaScripter,可能都应用过类,如:class{},等定义的一系列方法, 但是初学者看是学习js的时候,经常会看到这样一句话,那就是Ja ...

随机推荐

  1. OC中的多继承

    可以间接实现,方法有: 1.消息转发 2.协议 3.组合模式 4.代理 5.分类 直接上code,分别说明集中方法的实现 一.消息转发 消息转发可以参考我的另外一篇博客:http://www.cnbl ...

  2. Centos7 下面安装 MySql 客户端

    Workench 是官发发布的Mysql客户端,是Linux下面比较通用的了, 如果使用X界面,可以试着熟悉下. 下载链接: http://cdn.mysql.com//Downloads/MySQL ...

  3. 用flashfxp做ftp镜像同步

    简单说,用flashfxp建立上传或者下载队列,然后设定一个定时任务来处理这个队列,就能同步下载或上传制定的目录了. 本人遇到的需求只需要做同步上传,记录如下: 开发者PC ---> 国内win ...

  4. 《你不常用的c#之XX》

    你不常用的c#之一>:略谈unsafe http://blog.csdn.net/robingaoxb/article/details/6199508 <你不常用的c#之二>:略谈G ...

  5. 【转载】在IT界取得成功应该知道的10件事

     在IT界取得成功应该知道的10件事 2011-08-11 13:31:30 分类: 项目管理 导读:前面大多数文章都是Jack Wallen写的,这是他的新作,看来要成为NB程序员还要不停的自我总结 ...

  6. (转)EasyUI-datagrid-自动合并单元格

    1.目标 1.1表格初始化完成后,已经自动合并好需要合并的行: 1.2当点击字段排序后,重新进行合并: 2.实现 2.1 引入插件 /** * author ____′↘夏悸 * create dat ...

  7. 【ZOJ 3929】Deque and Balls(普通dp)

    题意:给出一个序列,按照顺序一个一个放入双端队列(可以放在头部也可以放在尾部),一个队列的美丽指数就是数列中a[i]>a[i+1]的个数,求美丽指数的期望*2^n的值. 解题思路:方便起见,我们 ...

  8. Ajax我选择这样入门

    什么是AJAX? AJAX的意思就是异步的JavaScript和XML.简而言之,它是使用XMLHttpRequest对象与服务器端通信的脚本语言.它可以发送及接收各种格式的信息,包括JSON.XML ...

  9. 如何在Android应用中引入外部网页

    在某些情况下,我们需要在Android应用中引入外部网页,这里记录一下如何操作(其实很简单^.^). 先介绍一下开发环境: 开发工具:Android Studio 1.5 SDK API版本:17 操 ...

  10. CentOS 6.5移除openJDK及JDK安装环境变量配置及JDK版本切换

    一.查找已经安装的open JDK [root@localhost ~]# rpm -qa|grep jdk java--openjdk-.el6_3.x86_64 java--openjdk-1.7 ...