下面全面介绍封装和信息隐藏。

  通过将一个方法或属性声明为私用的,可以让对象的实现细节对其它对象保密以降低对象之间的耦合程度,可以保持数据的完整性并对其修改方式加以约束。在代码有许多人参与设计的情况下,这也可以使代码更加可靠、更易于调试。

  不像其它语言,javascript中没有类似private这种关键字。我们将使用闭包的概念来创建只允许从对象内部访问的方法和属性。

  封装之利:封装保护了内部数据的完整性。通过将数据的访问途径限制为取值器和赋值器这两个方法,可以获得对取值和赋值的完全控制。通过只有公开那些在接口规定的方法,可以弱化模块间的耦合。使用私用变量也有助于避免命名空间冲突。如果一个变量在代码中其他地方都不能被访问,你就不用老担心它是否与程序中其它地方的对象或函数重名并因此造成问题。

封装弊端:很难进行单元测试。过度封装降低灵活性。封装是一门技术活,也是一门艺术活。

  创建对象的基本模式:

  ① 门户大开型对象

  所有属性和方法都是公开的、可访问的。

var Book = function(isbn,title,author) {
if(isbn == undefined) throw new Error("....");
this.isbn = isbn;
this.title = title||'No title specified';
this.author = author||'No author specified';
} Book.prototype.display = function() {
....
}; //增强版还可以是这样的:将Book.prototype设为一个对象字面量 Book.prototype = {
checkIsbn: function(isbn) {
....
}, display: function() {
...
}
}; //再次增强版,为了保护内部的数据结构,为每个属性都提供了取值器和赋值器方法 Book.prototype = {
checkIsbn: function(isbn) {
....
},
getIsbn: function() {
return this.isbn;
},
setIsbn: function(isbn) {
if(!checkIsbn(isbn)) throw new Error("..");
this.isbn = jsbn;
}, getTitle: function() {
return this.title;
},
setTitle: function() {
this.title = title||"No title specified";
},
....
display: function() {
....
}
};

  需要明确的是:虽然我们为设置属性提供了赋值器方法,但那些属性仍然是公开的,可以被直接设置,而在这种方案中却无法阻止这种行为。上述方法的简单性可嘉,却无法避免内部数据被破坏。怎么改进呢?

  改进:

  a. 使用命名规范区别私用变量,比如采用下划线命名规范,表明一个属性(或方法)仅供对象内部使用:道理很简单,用命名方式提醒对方,这是一个私有量,但是愿望是美好的,事实未必如你所愿。

  b. 利用作用域、嵌套函数、和闭包:javascript中,只有函数具有作用域。

function foo() {
var a = 10; function bar() {
a *= 2;
return a;
}
return bar;
} var baz = foo();
baz(); //
baz(); //
baz(); // //闭包实现私有成员
var Book = function(newIsbn,newTitle,newAuthor) {
//私有属性
var isbn,title,author; //这也再次证明了this.isbn实际上绑定到了window上,如果不是通过new方法来实例对象的话
//私有方法
function checkIsbn(isbn) {
......
}
//特权方法
this.getIsbn = function() {
return isbn;
};
this.setIsbn = function(newIsbn) {
if(!checkIsbn(newIsbn)) throw new Error("..");
isbn = newIsbn;
};
.....
//构造函数代码
this.setIsbn(newIsbn);
this.setTitle(newTitle);
}; //公共方法,不是特权方法
Book.prototype = {
display: function() {
....
}
};

  说明:对于特权方法我们都加了关键字this,因为这些方法都定义在Book构造器的作用域中,所以可以访问私有属性。

  任何不需要直接访问私用属性的方法都可以像原来那样在Book.prototype中声明。它不需要直接访问任何私有属性,因为它可以通过调用getIsbn()来进行间接访问。只有那些需要直接访问私有成员的方法才应该被设计为特权方法。但特权方法太多又会占用过多内存,因为每个对象实例都包含了所有特权方法的副本。

  ② 更多高级对象创建模式

  利用静态方法和属性,消除副本。

  大多数方法和属性所关联的是类的实例,而静态成员所有关联的则是类本身。换句话说,静态成员是在类的层次上操作,而不是在实例的层次上操作。每个静态成员是直接通过类对象访问。

var Book = (function() {
//私有静态成员
var numOfBooks = 0;
//私有静态方法
function checkIsbn(isbn) {
....
} //返回构造器
return function(newIsbn,newTitle,newAuthor) {
//私有属性
var isbn,title,author;
//私有方法
function checkIsbn(isbn) {
......
}
//特权方法
this.getIsbn = function() {
return isbn;
};
this.setIsbn = function(newIsbn) {
if(!checkIsbn(newIsbn)) throw new Error("..");
isbn = newIsbn;
};
.....
//构造函数代码
numOfBooks++;
this.setIsbn(newIsbn);
this.setTitle(newTitle); }
})(); //看到这对括号没^_^想想是什么用意吧
//公有静态方法
Book.convertTotitleCase = function(inputString) {
....
}; //公有非特权方法
Book.prototype = {
display: function() {
....
}
};

  在实例化Book时,所调用的是这个内层函数,外层那个函数只是用于创建一个可以用来存放静态私用成员的闭包。

  checkIsbn被设计成静态方法。因为为Book的每个实例都生成这个方法的一新副本毫无道理。

  要判断一个私用方法是否应该被设计成静态方法,经验就是:看它是否需要访问任何实例数据。如果它不需要要,那么就将其设计为静态方法更为高效。

  

  温馨提醒:别看例子看晕了,如果用一下印象会更深刻。~话说,你还记得那对括号吗?就是Book定义完成后那对括号。你知道封装好的对象是怎么运行怎么用的吗?且看下面的例子,运行一下,输出结果,一目了然:

<!doctype html>
<html>
<head>
<script>
var Book = (function() {
//私有静态成员
var numOfBooks = 0;
//私有静态方法
function checkIsbn(isbn) { } //返回构造器
return function(newIsbn,newTitle,newAuthor) {
//私有属性
var isbn,title,author;
//私有方法
function checkIsbn(isbn) {
return true; //测试用
}
//特权方法
this.getIsbn = function() {
return isbn;
};
this.setIsbn = function(newIsbn) {
if(!checkIsbn(newIsbn)) throw new Error("");
isbn = newIsbn;
alert(isbn); //测试用
}; //构造函数代码
numOfBooks++;
this.setIsbn(newIsbn);
}
})(); //看到这对括号没^_^想想是什么用意吧
//公有静态方法
Book.convertTotitleCase = function(inputString) { }; //公有非特权方法
Book.prototype = {
display: function() { }
}; var ex1 = Book("001","001","001"); //测试用
var ex2 = Book("002","002","002"); //测试用
</script>
</head>
<body> </body>
</html>

  

深入js的面向对象学习篇(封装是一门技术和艺术)——温故知新(二)的更多相关文章

  1. 深入js的面向对象学习篇(继承篇)——温故知新(三)

    写这篇有关继承的文章时,突然想起,几天前的面试.因为习惯在学习知识的时候加上自己的理解,很喜欢用自己话来解释,于是乎当面试被问起继承原理时,噼里啪啦一大堆都是自己组织的话,(也可能是因为个人紧张.外加 ...

  2. 深入js的面向对象学习篇——温故知新(一)

    在学习设计模式前必须要知道和掌握的***. 为类添加新方法: Function.prototype.method = function(name,fn) { this.prototype[name] ...

  3. 【js】面向对象学习资料

    1.面向对象模式: https://m.jb51.net/article/74549.htm 2.面向对象基础篇 http://www.cnblogs.com/chiangchou/p/js-oop1 ...

  4. Java基础学习篇---------封装

    一.类和对象分配内存 二.Java中的内部类  : 可以直接去访问外部类的所有属性(包括私有成员) 1.Java中成员内部类 (1).内部类的方法可以直接访问外部类的类中的所有成员变量 (2).外部类 ...

  5. js面向对象学习 - 对象概念及创建对象

    原文地址:js面向对象学习笔记 一.对象概念 对象是什么?对象是“无序属性的集合,其属性可以包括基本值,对象或者函数”.也就是一组名值对的无序集合. 对象的特性(不可直接访问),也就是属性包含两种,数 ...

  6. js学习篇1--数组

    javascript的数组可以包含各种类型的数据. 1. 数组的长度 ,直接用 length 属性; var arr=[1,2,3]; arr.length; js中,直接给数组的length赋值是会 ...

  7. js面向对象学习

    纯属笔记,加强记忆,不是教程,欢迎纠错,没有逻辑,不太适合学习使用. -------------- 继承多态等太多概念难以理解,还是从实践中慢慢学吧!争取能大致看懂网上的开源的代码. -------- ...

  8. 我的JS 中级学习篇

    在codefordream上进入中级学习后,感觉立马从js的基础学习往前跳了好远,上面的东西好像都是第一次看到一样.这时候才发现,说来也曾接触过js,但是这时候才发现对js的认识就停在知道两点:js中 ...

  9. JavaScript--我发现,原来你是这样的JS:面向对象编程OOP[2]--(创建你的那个对象吧)

    一.介绍 我们继续面向对象吧,这次是面向对象编程的第二篇,主要是讲创建对象的模式,希望大家能从博客中学到东西. 时间过得很快,还是不断的学习吧,为了自己的目标. 二.创建对象 1.前面的创建对象方式 ...

随机推荐

  1. JAVA开发:分享一些SpringMvc+Ibatis+spring的框架使用心得

    近期不在做.net的项目,而是使用java作为开发语言,就想着要用springmvc开发了,由于前些年也用过struts1/2+hibernate/ibatis+spring开发过项目,因此是有些底子 ...

  2. Messenger实现Android IPC

    当Service不需要支持并发操作时Messenger会非常有用.Messenger类使用Handler执行每个传入的消息,所有客户端的调用都按顺序运行在同一个线程上,这和AIDL是有区别的,AIDL ...

  3. Android实现双进程守护 (转)

    做过android开发的人应该都知道应用会在系统资源匮乏的情况下被系统杀死!当后台的应用被系统回收之后,如何重新恢复它呢?网上对此问题有很多的讨论.这里先总结一下网上流传的各种解决方案,看看这些办法是 ...

  4. 如何设置win7任务栏的计算机快速启动

    win7默认会有一个资源管理器的快速启动栏,但是点击的时候会打开“库”,你可能一般不会用这个库,想打开计算机怎么办呢? 其实很简单,再按住shift的同时右键资源管理器的这个快速启动项,然后会出现菜单 ...

  5. JAVA 实现通过URL下载文件到本地库

    /** * TODO 下载文件到本地 * @author nadim * @date Sep 11, 2015 11:45:31 AM * @param fileUrl 远程地址 * @param f ...

  6. HTML+CSS学习笔记(3)- 认识标签(2)

    HTML+CSS学习笔记(3)- 认识标签(2) 1.使用ul,添加新闻信息列表 在浏览网页时,你会发现网页上有很多信息的列表,如新闻列表.图片列表, 这些列表就可以使用ul-li标签来完成.ul-l ...

  7. switch的case中不能做定义

    switch的case中不能做定义 只能给语句 error: a label can only be part of a statement and a declaration is not a st ...

  8. Fuck Flyme Theme

    转载说明 本篇文章可能已经更新,最新文章请转:http://www.sollyu.com/fuck-flyme-theme/ 说明 本插件仅用于魅蓝Note, MX3, MX4, MX4 PRO它机型 ...

  9. DCL_数据库控制语言

    DCL(Data Control Language)              -------是数据库控制语言.是用来设置或更改数据库用户或角色权限的语句,包括(grant,deny,revoke等) ...

  10. CSS的引入方式

    再用HTML编写的文本中,有是没能达到我们想要的效果,此时此刻我们可以用过引用CSS来控制!这不仅使得效果好而且代码层次清晰.CSS的引入方式可以分为四类: 1.链入外部样式表,就是把样式表保存为一个 ...