深入js的面向对象学习篇(封装是一门技术和艺术)——温故知新(二)
下面全面介绍封装和信息隐藏。
通过将一个方法或属性声明为私用的,可以让对象的实现细节对其它对象保密以降低对象之间的耦合程度,可以保持数据的完整性并对其修改方式加以约束。在代码有许多人参与设计的情况下,这也可以使代码更加可靠、更易于调试。
不像其它语言,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的面向对象学习篇(封装是一门技术和艺术)——温故知新(二)的更多相关文章
- 深入js的面向对象学习篇(继承篇)——温故知新(三)
写这篇有关继承的文章时,突然想起,几天前的面试.因为习惯在学习知识的时候加上自己的理解,很喜欢用自己话来解释,于是乎当面试被问起继承原理时,噼里啪啦一大堆都是自己组织的话,(也可能是因为个人紧张.外加 ...
- 深入js的面向对象学习篇——温故知新(一)
在学习设计模式前必须要知道和掌握的***. 为类添加新方法: Function.prototype.method = function(name,fn) { this.prototype[name] ...
- 【js】面向对象学习资料
1.面向对象模式: https://m.jb51.net/article/74549.htm 2.面向对象基础篇 http://www.cnblogs.com/chiangchou/p/js-oop1 ...
- Java基础学习篇---------封装
一.类和对象分配内存 二.Java中的内部类 : 可以直接去访问外部类的所有属性(包括私有成员) 1.Java中成员内部类 (1).内部类的方法可以直接访问外部类的类中的所有成员变量 (2).外部类 ...
- js面向对象学习 - 对象概念及创建对象
原文地址:js面向对象学习笔记 一.对象概念 对象是什么?对象是“无序属性的集合,其属性可以包括基本值,对象或者函数”.也就是一组名值对的无序集合. 对象的特性(不可直接访问),也就是属性包含两种,数 ...
- js学习篇1--数组
javascript的数组可以包含各种类型的数据. 1. 数组的长度 ,直接用 length 属性; var arr=[1,2,3]; arr.length; js中,直接给数组的length赋值是会 ...
- js面向对象学习
纯属笔记,加强记忆,不是教程,欢迎纠错,没有逻辑,不太适合学习使用. -------------- 继承多态等太多概念难以理解,还是从实践中慢慢学吧!争取能大致看懂网上的开源的代码. -------- ...
- 我的JS 中级学习篇
在codefordream上进入中级学习后,感觉立马从js的基础学习往前跳了好远,上面的东西好像都是第一次看到一样.这时候才发现,说来也曾接触过js,但是这时候才发现对js的认识就停在知道两点:js中 ...
- JavaScript--我发现,原来你是这样的JS:面向对象编程OOP[2]--(创建你的那个对象吧)
一.介绍 我们继续面向对象吧,这次是面向对象编程的第二篇,主要是讲创建对象的模式,希望大家能从博客中学到东西. 时间过得很快,还是不断的学习吧,为了自己的目标. 二.创建对象 1.前面的创建对象方式 ...
随机推荐
- ZooKeeper(3.4.5) - 原生 API 的简单示例
一.创建会话 1. 创建一个基本的ZooKeeper会话实例 package com.huey.dream.demo; import java.util.concurrent.CountDownLat ...
- ASP.NET中处理异常的几种方式
1.程序中使用try catch 对于预知会发生异常的代码段使用try catch主动捕获异常,适用于提示给用户或跳转到错误页面,或者通过其它方式处理异常(日志.通知等). int i = 10; i ...
- java开发:分享一下MemCached的使用
在项目开发中,有些不经常修改的数据,我们通常都会选择使用缓存.其中一种方式,就是memcached. windows系统中,我们需要下载并安装memcached. 地址如:D:\memcached\m ...
- Java I/O第二篇 之 (缓冲流 随机流 数组流 数据流)
1:缓冲流 BufferedReader BufferedWriter 具有较强的读写能力,能单独读写一行数据,能够减少对硬盘的访问次数. /** * 缓冲流 能够增强对问价数据的可读性,减少访问读 ...
- Crontab使用mailx的一点发现
要用到Crontab定时任务去执行一个Shell脚本监控Linux系统资源并且当一些数字超过预设的话发送邮件警告.首先是linux的sendmail功能无法满足我们使用SMTP服务器并且指定发送者(E ...
- 本招聘信息2014年长期有效!杭州派尔科技高薪诚聘android开发(10K-20K),web前端开发(8K-15K),IOS开发(15K-25K)
杭州派尔科技有限公司发展至今,离不开员工的无私奉献和辛勤耕耘,在努力创造更好成绩的同时,公司也不忘回馈每一位员工的努力与付出.1.全面的绩效考核机制,让发展空间近在眼前!公司力争让每一位员工都了解自己 ...
- javascript笔记——jQuery插件开发的几种方式
jQuery插件开发分为两种: 1 类级别 类级别你可以理解为拓展jquery类,最明显的例子是$.ajax(...),相当于静态方法. 开发扩展其方法时使用$.extend方法,即jQuery.e ...
- 4月8日学习笔记(js基础)
<script>标签放在<body>和<head> 放在 <head></head> 里的会比放在 <body></bod ...
- xml的生成与解析_老师笔记
使用序列化器生成一个xml文件 //1,初始化一个xml文件的序列化器 XmlSerializer serializer = Xml.newSerializer(); //2.初始化序列器参数 Fil ...
- Spring boot 1.3.5 RELEASE 官方文档中文翻译--目录
说明: 打算利用闲暇时候翻译一下Spring boot的官方文档,翻译的版本是1.3.5 RELEASE. 做这件事的目的呢有四: 国内中文的Spring boot资料实在不多,希望能给后来人一点小小 ...