JavaScript中的面向对象的讨论(转)
前言
今天,WEB2.0时代的到来,给了JavaScript又一次大展身手的机会。Web2.0借助JavaScript技术,使得客户端的Web体验更加丰富多彩,同时JavaScript面对的问题域也变得错综复杂起来,JavaScript代码也随着Web页面的多样化和功能的丰富而快速膨胀。以前的过程式的JavaScript开发方法已经不能适应Web2.0的开发需求,需要一种更先进的设计方法来指导JavaScript的开发,这就是这里我们要讨论的面向对象。
面向对象概念的提出,是软件开发工程发展的一次革命,有了面向对象,很多复杂的大型应用程序的开发可以简化。可以说,有了面向对象,我们手里才得到了一把真正的利刃,可以得心应手的处理复杂而又规模庞大的问题域。
面向对象的三个基本特征是:
- 封装-把自己的数据和方法封装在对象内部,并让私有的数据和方法在对象外部不可见,而共有的数据和方法在对象外部可见。
- 继承-在无需重新修改原来对象的前提下,让另一个对象获得原对象的属性和方法的能力
- 多态-子类可以定义与父类具有相同signature的方法。
因此我们就这三个基本特征展开JavaScript面向对象的讨论。
基本概念
JavaScript语言对对象提供了天然支持。数组(Array)是对象,函数(function)是对象。但是JavaScript不是一种真正意义上的面向对象语言。这是因为JavaScript并不具备完整的面向对象三个基本特征。
在正式开始讨论之前,首先要对JavaScript的类,成员变量,成员函数,类变量,类方法这几个概念进行说明。
Ÿ 类
JavaScript中并没有类的概念,也就是说,JavaScript中并没有语法支持“类”。因此,JavaScript中的类其实都是使用function来模拟的。
类的定义:
function Circle(r){
this.r = r;
}
类的实例化:var circle = new Circle(3);
Ÿ 成员变量
成员变量可以通过多种方式定义:
构造器中: this.r = r;
对象:circle.name="my circle";
Ÿ 成员函数
成员函数也可以通过多种方式定义:
构造器中:
function Circle(r){
this.r = r;
function sqr(){
return r*r;
}
}
prototype:
Circle.prototype.getName=function(){
return this.name;
}
Ÿ 类变量
类变量是属于类的变量。就像java里用static声明的变量,可以直接用类就可以访问。由于类变量是属于类的,因此所有这个类的实例也可以访问这个变量。因此,任何实例都不应该修改类变量(JavaScript中没有类似java的final关键字使类变量不可变)。类变量与通过prototype定义的变量的功能类似,但是他们的访问方式不同。
访问prototype变量:Circle.prototype.PI=3.14;
访问类变量:Circle.PI=3.14;
//使用prototype里的变量
Circle.prototype.area1 = function(){
return this.PI*this.r*this.r;
}
//使用类变量
Circle.prototype.area2 = function(){
return Circle.PI*this.r*this.r;
}
Ÿ 类方法
类方法是直接在类上定义的方法。注意,在类方法中不能使用this关键字,就像是在java的static方法中,不能使用this一样。
Circle.max = function(a,b){
return a.r>b.r?a:b;
}
var maxCircle = Circle.max(new Circle(1),new Circle(2));
面向对象的三个基本特性
在有了上面的知识以后,下面就开始依据面向对象三个基本特征,对JavaScript的面向对象特性进行讨论。
1. 封装
JavaScript中,所有元素都可以认为是对象。这就是JavaScript对对象的天然支持。在JavaScript的对象里,还可以定义方法(function),数据变量(var)。这样,JavaScript对象可以把数据和方法封装在对象内部。
JavaScript是如何实现对象数据的访问控制的呢?JavaScript跟别的面向对象语言一样,也是通过function和变量的不同的声明方式而实现访问控制的。
Ÿ 公有成员
对象的成员都是公有成员,任何函数都可以访问,修改或删除这些成员。有两种主要途径给对象添加公有成员:
Ø 构造器:
构造器中,使用this变量来向对象添加成员。注意,这里只是用this变量添加了属性成员。用this变量添加的function成员,而特权成员(见下文解释)而不是公有成员。
function Container(param){
this.member = param;
}
Ø 原型:
使用prototype添加成员是很常用的一种给对象添加公共成员的方式:
Container.prototype.stamp = function(string){
return this.member+string;
}
Ÿ 私有成员
私有成员要由构造器生成。构造器的参数,以及其中通过var声明成员都是私有成员。私有成员是无法被公有成员访问的。但是公有成员可以通过一些技巧来访问私有成员。例如,
function Container(param){
function dec(){
if(secret>0){
secret-=1;
return true;
}else{
return false;
}
}
this.member = param;
var secret = 3;
var self = this;
}
在上面的代码例子中,有三个私有成员:param,secret,self。它们在对象内部,并且在对象外部不能访问这三个成员,同时也不能被对象的公有方法访问。他们只对私有成员可见。
这里有一个技巧,就是定义了一个私有的self变量。通过这个self变量,可以在让私有成员中访问公有成员。
Ÿ 特权成员
特权成员实际上是特指function成员。特权成员可以访问私有成员(变量和方法),同时它对公共域也是可见的。可以删除或替换一个特权成员,但是不能对他进行修改。
特权方法是用this在构造器中定义的。
function Container(param){
function dec(){
if(secret>0){
secret-=1;
return true;
}else{
return false;
}
}
this.member = param;
var secret = 3;
var self = this;
//特权成员
this.service = function(){
if(dec()){
return self.member;
}else{
return null;
}
};
}
上面的代码片段中,service方法就是一个特权成员。可以看到,在service方法中,调用了私有方法dec(),而dec又访问了私有变量secret.
2. 继承
JavaScript继承问题一直是网上被讨论最热烈的一个JavaScript问题。在详细讨论JavaScript的继承之前,我们先看一下“继承”的概念。
继承,让子类具备父类的特性。继承,描述的是类型层面上而不是个体层面上的特性。因此,继承,只应该是描述类型的,也就是说,只能是类之间存在继承关系,而对象实体之间是不存在继承关系的。
由于JavaScript并不是很清晰(类跟对象没有明显的区分),因此导致JavaScript中的继承实现要大费周折。很多人为JavaScript想出了各种各样的实现继承的方法,包括:构造器继承法,原型继承法,实例继承法,附加继承法。
这里不去详细讨论每一种继承的实现思路。
在《JavaScript权威指南1.5》中列出的是prototype继承。
function SubCircle(x, y, r) {
this.x = x;
this.y = y;
this.r =r;
}
SubCircle.prototype = new Circle(0);
这种继承方式,会有一点问题,就是原来在SubCircle的prototype中定义的方法和属性丢失。
在prototype1.5 framework中,通过属性复制定义另一中继承方式。核心概念就是把Circle的prototype中的所有成员复制到SubCircle中,这样可以确保SubCircle的prototype中的成员不会丢失,但是这样也有个问题,就是Circle中定义的公有成员,特权成员并没有被继承到SubCircle中。
为了解决这个问题,可以综合上面两种继承的有点,进行如下的实现:
3. 多态
首先看一下例子:
///////////define: Cricle//////////////////
function Circle(r) {
this.r = r;
}
Circle.PI = 3.14;
Circle.prototype.PI = 3.14;
Circle.prototype.area = function() { return Circle.PI*this.r*this.r; }
Circle.prototype.area2 = function() { return this.PI*this.r*this.r; }
//// test
c = new Circle(3);
//alert("area1 :"+c.area());
//alert("area2 :"+c.area2());
Circle.max = function(a, b) { return a.r>b.r ? a.r : b.r; }
//alert("max is "+Circle.max(new Circle(1), new Circle(3)));
c1 = new Circle(1);
c2 = new Circle(1);
c2.PI = 100;//Circle.prototype.PI=100;
//alert("c1.area1 "+c1.area());
//alert("c1.area2 "+c1.area2());
//alert("c2.area1 "+c2.area());
//alert("c2.area2 "+c2.area2());
////////////////////////define: SubCircle //////////////////
function SubCircle(x, y, r) {
this.x = x;
this.y = y;
this.r = r;
}
SubCircle.prototype = new Circle(0);
SubCircle.prototype.PI = 100;
SubCircle.prototype.move2 = function(x, y) { this.x = x; this.y = y;}
SubCircle.prototype.area = function() { return this.PI*this.r*this.r*this.r; }
//// test
sc = new SubCircle(0,0,2);
alert(sc.area());
调用sc.area()的执行顺序是:
sc.PI->sc.prototype.PI->100;
sc.area()->sc.prototype.area()->SubCircle(0,0,2).area()
从上面的调用顺序可以看到,SubCircle的调用过程中,只要属性和方法在子类中存在,就完全用子类的属性和方法。
如果要使用父类的属性和方法怎么办呢?这就要用到继承部分的支持。在继承的时候,子类的prototype中增加了一个属性superClass,这个superClass就是父对象的引用。因此就可以通过superClass调用父对象的属性和方法了。
命名空间
随着功能的增加,JavaScript代码也会变的越来越复杂,那么给JavaScript增加命名空间就显得尤为重要了。
JavaScript语言中没有对命名空间提供直接的支持,因此只有通过模拟实现命名空间。具体实现是使用闭包特性,使JavaScript代码位于某些特定的Function内。下面是命名空间的代码片段:
//最外层的包
var laputa = {};
//在laputa包内部定义了两个包:lang,util
laputa.lang={};
laputa.util = {};
//在lang包里定义了String类,
laputa.lang.String = {};
//String类的trim方法
laputa.lang.String.prototype.trim = function(){
return this.replace(/(^\s*)|(\s*$)/g, "");
};
//String类的toUpperCase方法
laputa.lang.String.prototype.toUpperCase = function(){
return this.toUpperCase();
}
//在util包定义了DocumentUtil类
laputa.util.DocumentUtil = {};
//DocumentUtil类的$方法
laputa.util.DocumentUtil.$ = function(id){
return document.getElementById(id);
}
//DocumentUtil类的$v方法
laputa.util.DocumentUtil.$v = function(id){
var el = laputa.util.DocumentUtil.$(id);
if(el){
return el.value;
}
return null;
}
JavaScript中的面向对象的讨论(转)的更多相关文章
- JavaScript从初见到热恋之深度讨论JavaScript中的面向对象。
JavaScript中的面向对象.面向对象的三个基本特征:封装.继承.多态. 1.封装 js的封装如下 定义Person类 function Person(name,age,sex) { this.n ...
- 前端开发:面向对象与javascript中的面向对象实现(一)
前端开发:面向对象与javascript中的面向对象实现(一) 前言: 人生在世,这找不到对象是万万不行的.咱们生活中,找不到对象要挨骂,代码里也一样.朋友问我说:“嘿,在干嘛呢......”,我:“ ...
- 前端开发:面向对象与javascript中的面向对象实现(二)构造函数与原型
前端开发:面向对象与javascript中的面向对象实现(二)构造函数与原型 前言(题外话): 有人说拖延症是一个绝症,哎呀治不好了.先不说这是一个每个人都多多少少会有的,也不管它究竟对生活有多么大的 ...
- 简单分析JavaScript中的面向对象
初学JavaScript的时候有人会认为JavaScript不是一门面向对象的语言,因为JS是没有类的概念的,但是这并不代表JavaScript没有对象的存在,而且JavaScript也提供了其它的方 ...
- 如何理解并学习javascript中的面向对象(OOP) [转]
如果你想让你的javascript代码变得更加优美,性能更加卓越.或者,你想像jQuery的作者一样,写出属于自己优秀的类库(哪怕是基于 jquery的插件).那么,你请务必要学习javascript ...
- 前端开发:javascript中的面向对象
前端开发:面向对象与javascript中的面向对象实现(一) 面向对象理解: 面向对象是一种对现实世界理解和抽象的方法,是一种先进的程序设计理念,是一种比较抽象的,多形态的设计模式.我们可以这么理解 ...
- 深入理解javascript中实现面向对象编程方法
介绍Javascript中面向对象编程思想之前,需要对以下几个概念有了解: 1. 浅拷贝和深拷贝:程序在运行过程中使用的变量有在栈上的变量和在堆上的变量,在对象或者变量的赋值操作过程中,大多数情况先是 ...
- JavaScript中的面向对象程序设计
本文内容目录顺序: 1.Object概念讲述: 2.面向对象程序设计特点: 3.JavaScript中类和实例对象的创建: 4.原型概念: 5.原型API: 6.原型对象的具体使用:7.深入理解使用原 ...
- 领悟 JavaScript 中的面向对象
JavaScript是基于对象的语言,我们可以使用面向对象的思想去开发js代码. JavaScript是基于对象的语言. 可以使用面向对象的思想,但是不少人对这一点理解得并不全面. 在 JavaScr ...
随机推荐
- JQuery简单实现图片轮播效果
很多页面都需要用到界面轮播,但是用原生js相对来说比较复杂,用jQuery实现效果比较迅速,写个简单的demo 1.首先在HTML页面要放置轮播图案位置插入div,这里写了轮播图片数量为3张,所以定义 ...
- UFLDL课程学习(一)
章节地址:http://ufldl.stanford.edu/tutorial/supervised/LinearRegression/ 章节名称:线性回归 (Linear Regression) 第 ...
- TextView过长显示省略号, TextView文字中间加横线
1.TextView显示的内容过长时自动显示省略号: 省略号的位置:android:ellipsize="end" 省略号在结尾android:ellipsize=" ...
- github修改自己的昵称
由于刚接触github,不会用,就随便写了个昵称,后来想改,却不知道从哪里改,到百度搜结果都是说不能修改的(这里就不吐槽百度了),还是直接上图吧. 点击Settings,然后跳转到下面界面,点击Acc ...
- Hbase常用操作
下面我们看看HBase Shell的一些基本操作命令,我列出了几个常用的HBase Shell命令,如 名称 命令表达式 创建表 create '表名称', '列名称1','列名称2','列名称N' ...
- java加载配置文件
有时候一些变量可能会变,但直接写在程序代码中不好,因为有时候需要改的时候要改动源代码,这时候可以使用配置文件来管理.比如数据库中的端口和密码. 1. 把.properties配置文件放在src目录下. ...
- centos6 下用yum 安装 nginx
以下操作在Cento6.4 系统下实现 一.更新使用163的库 vi /etc/yum.repos.d/CentOS-Base.repo yum update [base] name=CentOS-$ ...
- jquery中attr、prop、data
在高版本的jquery中获取标签的属性,可以使用attr().prop().data(),那么这些方法有什么区别呢? 对于HTML元素本身就带有的固有属性,在处理时,使用prop方法. 对于HTML元 ...
- idhttp post 上传或下载时显示进度条
通过 idhttp 带进度条上传演示一下,下载和上传原理差不多,说明一下下面例子中的的idhttp 是动态创建的 第一步:添加一个StatusBar或者gauge 进度条,这2个都可以.我用的是 st ...
- Oracle database启动过程分析
实例跟数据库的区别 实例(instance)是内存中的一块区域和一组后台进程的集合.它的作用是维护数据库文件的.而数据库(database)则是指存放数据的数据库文件.它是一系列格式化的数据的集合.它 ...