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

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

  不像其它语言,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. IntelliJ IDEA 13.x 下使用Hibernate + Spring MVC + JBoss 7.1.1

    从2004年开始做.NET到现在.直到最近要做一些JAVA的项目,如果说100个人写一篇关于.NET的文章,估计这10个人写的内容都是一样.但是如果说10个人写Java的文章,那真的是10个人10种写 ...

  2. 我的EntityFramework(2):简单的数据查询

    原文:我的EntityFramework(2):简单的数据查询 在上一篇博文中,已经搭建了基本的框架,接下来就进行简单的数据查询,这里主要用了Linq 常见的数据集查询 var companyList ...

  3. IOS UI 笔记整理回顾

    注意手势会冒泡上抛,一个view没有实现的手势,如果父类view有实现,父视图就处理,如果不想让父视图处理,就把本视图添加到底层window上 setMasksToBounds:YES imageVi ...

  4. CentOS 7 下Docker的安装

    笔者是刚入行1年的新鸟,近期公司开始推Docker技术.这个系列的文章都是基于CentOS7系统下进行讲解的. Docker简介 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及 ...

  5. 【转载】茶叶蛋干货!《超容易的Linux系统管理入门书》(连载十)进行动态主机配置DHCP

    使用动态主机配置协议DHCP(Dynamic Host Configuration Protocol)则可以避免网络参数变化后一些繁琐的配置,客户端可以从DHCP服务端检索相关信息并完成相关网络配置, ...

  6. 暑假集训(4)第一弹 -----递推(Hdu2039)

    题意梗概:fff团团员小A想退团了,不过要退团,他必须绘制出贤者法阵,以证明他有资格不受大fff之灵的监督 并退团,小A他现在要开始收集材料了,但是,他不清楚应该买多少份材料. 虽然你并不想帮他退团, ...

  7. poj 2431 Expedition

    Expedition Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 12980   Accepted: 3705 Descr ...

  8. 《Spring3.0就这么简单》

    第一章 认识Spring 1.Spring提供的IOC容器,是Spring大杀器之一.容器将对象之间的依赖关系交给Spring进行控制,采用配制的方式对依赖关系进行描述,由Ioc容器负责依赖类之间的创 ...

  9. checkbox批量选中,获取选中的项的值

    <!doctype html><html lang="en"> <head>  <meta charset="UTF-8&quo ...

  10. centos6.4下安装freetds使php支持mssql

    centos版本:6.4 php版本5.3.17 没有安装之前的情况:nginx+php+mysql+FPM-FCGI 接下来安装步骤如下: 1.打开http://www.freetds.org/,进 ...