javascript设计模式 封装和信息隐藏(上)


Posted in Javascript onJuly 24, 2012

本文分上下两部分,上部讲基本模式(basic patterns):完全暴露法,下划线标记法和使用闭包;下部讲高级模式(Advanced Patterns),如何实现静态方法和属性,常量还有其他一些知识点。

封装是面向对象语言很基本也是很有用的特性,虽然javascript也可以称的上是面向对象语言,但他对封装的支持并不是很好,不像其他语言,只要使用private、protected就可以实现。但这并不是说就没有办法了,下面我就介绍下如何在javascript中实现封装。
一、基本模式(basic patterns),主要包括三种方式:完全暴露法,下划线标记法和使用闭包。(闭包是个很重要,也是很难的概念,有兴趣的朋友可以去网上找资料,我博客里也转载了别人的文章)。

这里我们以book类作为例子,需要创建和初始化book类。

// Book(isbn, title, author) 
var theHobbit = new Book('0-395-07122-4', 'The Hobbit', 'J. R. R. Tolkien'); 
theHobbit.display(); // Outputs the data by creating and populating an HTML element.

1.完全暴露法:
创建book类可以用最传统的构造函数方式,
var Book = function(isbn, title, author) { 
if(!this.checkIsbn(isbn)) throw new Error('Book: Invalid ISBN.'); 

this.isbn = isbn; 

//代码中 || 的作用是 如果title无值,则会把'No title specified'赋给 this.title。这种方式很好用,大家可以在自己的代码中使用。 

this.title = title || 'No title specified'; 

this.author = author || 'No author specified'; 
} 
Book.prototype = { 

//验证isbn函数 

checkIsbn: function(isbn) { 


... 

}, 

//获取isbn 

getIsbn: function() { 


return this.isbn; 

}, 

//设置isbn 

setIsbn: function(isbn) { 


if(!this.checkIsbn(isbn)) throw new Error('Book: Invalid ISBN.'); 



this.isbn = isbn; 

}, 

//获取title 

getTitle: function() { 


return this.title; 

}, 

//设置title 

setTitle: function(title) { 


this.title = title || 'No title specified'; 

}, 

//获取作者 

getAuthor: function() { 


return this.author; 

}, 

//设置作者 

setAuthor: function(author) { 


this.author = author || 'No author specified'; 

}, 

//显示函数 

display: function() { 


... 

} 
};

 代码有点多,我在这里简单讲解下。javascript中创建类和c#,java有点不同,c#,java会把所有方法和属性包在一个类文件里面,比如说
public class book() 
{ 
private string isbn; 
public string ISBN 
{ 
set 
{ 


this.isbn=value; 


 } 


 get 


 { 



return this.isbn; 


 } 

} 
... 
private bool CheckIsbn(string isdn) 
{ 
...... 
} 
...... 
public void Display() 
{ 
...... 
} 
}

javascript也可以用这种方式,但是推荐使用我上面使用的把属性定义到类定义函数(或者叫构造函数),方法定义到prototype对象中,这种做法性能要好些,至于原因大家可以去google。

上面的js代码想实现的功能是,定义一个book类,类里面包括三个私有变量(或者叫属性)isbn,title,author,一个私有方法checkIsbn,几个公有方法getIsdn,setIsdn,...display。想法是好的,但是现实是残酷的,其实那些私有属性或者方法根本一点都不私有。比如说,theHobbit.isbn = '978-0261103283';你可以用这种方式为isbn赋值,不会报错而且绝对成功。原因就是javascript没有private方式去实现对特定对象的私有化。此外这种实现方式在使用时也会造成困惑,到底类的创建者想暴露哪些属性和方法呢?下面介绍第一种改进办法,下划线标记法。

2.下划线标记法:

var Book = function(isbn, title, author) { 
// Constructor code. 

this.setIsbn(isbn); 

this.setTitle(title); 

this.setAuthor(author); 
} 
Book.prototype = { 
 

//验证isbn函数 
 

_checkIsbn: function(isbn) { 


... 

}, 
 

//获取isbn 
 

getIsbn: function() { 

 


return this._isbn; 
 

}, 
 

//设置isbn 
 

setIsbn: function(isbn) { 

 


if(!this._checkIsbn(isbn)) throw new Error('Book: Invalid ISBN.'); 


 


this._isbn = isbn; 
 

}, 
 

...
 

//显示函数 
 

display: function() { 

 

... 
 

} 
};

其实就是在所有想实现私有的属性或者方法前面加了下划线_,没别的操作。这种方法并没有实现真正的私有化,theHobbit._isbn = '978-0261103283';这样操作照样成功,这种方式最大的意义在于告诉类的使用者,作者本意上想暴露哪些对象,不想暴露哪些。但是使用者是否按照作者的想法去做,作者是控制不了的。

那有没有办法实现真正的私有化呢,答案是有的,就是利用闭包。

3.使用闭包:

javascript之所以能实现真正的封装,是和他特有的函数作用域,函数支持内部函数,还有闭包分不开的。大家可以去网上搜集相关知识加深理解。

下面首先说的就是函数作用域,在javascript中如果在一个函数内部定义了一个变量,那么函数外部是没有办法访问的。其实在javascript中实现私有属性或者方法就是利用了它这一特殊属性。例子:

function foo() { 
var a = 10; 

function bar() { 


a *= 2; 

} 

bar(); 

return a; 
}

在上面的例子中函数foo在内部定义了变量a和方法bar,在foo外部是无法访问到a和bar的,但是因为a和bar都定义在foo内部,但bar是可以访问到a的。那么有没有办法能在foo外部访问到bar呢,答案是有的,就是使用闭包。
function foo() { 
var a = 10; 

function bar() { 


a *= 2; 


return a; 

} 

return bar; 
} 
var baz = foo(); // baz is now a reference to function bar. 
baz(); // returns 20. 
baz(); // returns 40. 
baz(); // returns 80. 
var blat = foo(); // blat is another reference to bar. 
blat(); // returns 20, because a new copy of a is being used.

这就是在前面提到的javascript函数支持内部函数。内部函数bar可以访问私有变量a,函数foo又把内部函数bar抛出给baz,baz就可以访问到内部变量a了,这就实现了闭包。大家一看也就明白了,这样其实就实现了私有变量和方法。回到我们前面的book例子,实现如下:
var Book = function(newIsbn, newTitle, newAuthor) { 
// implements Publication 

// Private attributes. 

var isbn, title, author; 

// Private method. 

function checkIsbn(isbn) { 


... 

} 

// 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() { 


... 

} 
};

上述代码就实现了 isbn, title, author和checkIsbn的私有化,外部是决定不能直接访问到的。如需访问 isbn, title, author只能通过对象级的方法getTitle,setTitle...。比如要给isbn赋值,只能用theHobbit.setIsbn = '978-0261103283';,如果你还用theHobbit._isbn = '978-0261103283';,对不起要报错了。

 好了,今天的内容就讲到这里了,希望对大家有帮助。
作者:下一站永远

Javascript 相关文章推荐
JavaScript 检测浏览器和操作系统的脚本
Dec 26 Javascript
JQuery live函数
Dec 24 Javascript
JQuery 返回布尔值Is()条件判断方法代码
May 14 Javascript
JavaScript中__proto__与prototype的关系深入理解
Dec 04 Javascript
有关于JS辅助函数inherit()的问题
Apr 07 Javascript
cookie 最近浏览记录(中文escape转码)具体实现
Jun 08 Javascript
在JavaScript里嵌入大量字符串常量的实现方法
Jul 07 Javascript
输入框点击时边框变色效果的实现方法
Dec 26 Javascript
vue2.0构建单页应用最佳实战
Apr 01 Javascript
Vue-cli Eslint在vscode里代码自动格式化的方法
Feb 23 Javascript
监听angularJs列表数据是否渲染完毕的方法示例
Nov 07 Javascript
jQuery实现带进度条的轮播图
Sep 13 jQuery
js+xml生成级联下拉框代码
Jul 24 #Javascript
40个新鲜出炉的jQuery 插件和免费教程[上]
Jul 24 #Javascript
基于jquery的跟随屏幕滚动代码
Jul 24 #Javascript
基于JQuery的类似新浪微博展示信息效果的代码
Jul 23 #Javascript
基于jquery自定义图片热区效果
Jul 21 #Javascript
Js四则运算函数代码
Jul 21 #Javascript
Javascript对象中关于setTimeout和setInterval的this介绍
Jul 21 #Javascript
You might like
php实现window平台的checkdnsrr函数
2015/05/27 PHP
详解PHP中instanceof关键字及instanceof关键字有什么作用
2015/11/05 PHP
php 多继承的几种常见实现方法示例
2019/11/18 PHP
node.js中的path.delimiter方法使用说明
2014/12/09 Javascript
基于Node.js的强大爬虫 能直接发布抓取的文章哦
2016/01/10 Javascript
jQuery UI Bootstrap是什么?
2016/06/17 Javascript
Vue.js原理分析之observer模块详解
2017/02/17 Javascript
node.js入门教程之querystring模块的使用方法
2017/02/27 Javascript
jquery实现折叠菜单效果【推荐】
2017/03/08 Javascript
微信小程序商城项目之淘宝分类入口(2)
2017/04/17 Javascript
Angular4学习笔记之实现绑定和分包
2017/08/01 Javascript
Easyui和zTree两种方式分别实现树形下拉框
2017/08/04 Javascript
解决Vue编译时写在style中的路径问题
2017/09/21 Javascript
nodejs实现套接字服务功能详解
2018/06/21 NodeJs
详解Vue.js iview实现树形权限表(可扩展表)
2018/09/30 Javascript
微信小程序实现左滑修改、删除功能
2020/10/19 Javascript
利用Webpack实现小程序多项目管理的方法
2019/02/25 Javascript
node.js +mongdb实现登录功能
2020/06/18 Javascript
探究一道价值25k的蚂蚁金服异步串行面试题
2020/08/21 Javascript
[03:31]DOTA2英雄基础教程 大地之灵
2013/12/17 DOTA
[02:14]2016国际邀请赛中国区预选赛Ehome晋级之路
2016/07/01 DOTA
使用基于Python的Tornado框架的HTTP客户端的教程
2015/04/24 Python
python实现红包裂变算法
2016/02/16 Python
Python+Socket实现基于UDP协议的局域网广播功能示例
2017/08/31 Python
基于python批量处理dat文件及科学计算方法详解
2018/05/08 Python
Python图像处理库PIL的ImageEnhance模块使用介绍
2020/02/26 Python
python实现爱奇艺登陆密码RSA加密的方法示例详解
2020/05/27 Python
纯CSS3实现带动画效果导航菜单无需js
2013/09/27 HTML / CSS
怀旧香味蜡烛:Homesick
2019/11/02 全球购物
Orlebar Brown官网:设计师泳裤和泳装
2020/12/08 全球购物
瑞典最大的儿童用品网上商店:pinkorblue.se
2021/03/09 全球购物
社区工作者先进事迹
2014/01/18 职场文书
遵纪守法演讲稿
2014/05/23 职场文书
2014年统计工作总结
2014/11/21 职场文书
大学运动会通讯稿
2015/07/18 职场文书
创业计划书之物流运送
2019/09/17 职场文书