JavaScript 面向对象编程(三)如何写类和子类
在JavaScript面向对象编程(一)原型与继承和JavaScript面向对象编程(二)构造函数和类中,我们分别讨论了JavaScript中面向对象的原型和类的概念。基于这两点理论,本篇文章用一个简单的例子来阐述如何在JavaScript中写类与子类。
几个面向对象的概念
实例属性:是每个对象所拥有的属性。比如对于一个Person类的对象而言,name、age等属性是每一个person所拥有的。而且,不同person的age和name可能不同。所以,在JavaScript中我们必须把实例属性加在对象上面。
实例方法:是类的实例所共享的方法。这些方法通过实例进行调用。比如所有的Person类的对象共享一个getName()方法,通过person对象调用这个方法获取对象的name属性的值。这个方法是实例对象共享的,所以把实例方法加在类的prototype上。
类属性与方法:这与传统面向对象语言中静态属性和方法类似。类属性与方法是类所拥有的,而非对象所拥有。在JavaScript所实现的类属性和类方法是通过“构造函数对象”获取。
基类方法调用:在子类的构造函数或者是子类所重载的方法中,调用基类相应方法。
现在用Person类和其子类Student类来阐述上面的概念。
定义一个类
var Person = function(name,age){
//instance property, which owns by the instance.
this.name = name;
this.age = age;
};
//Class methods and properties, owned by Class not by the instances. They are "static"
Person.YOUNG = 18;
//instance methods, which are shared by all the instances
Person.prototype.sayHello = function(){
console.log("Hello!");
console.log("I am " + this.name);
};
Person.prototype.isAdult = function() {
if(this.age >= Person.YOUNG){
return true;
}
else{
return false;
}
};
Person.prototype.grow = function(){
this.age = this.age + 1;
};
在Person类中,name和age是实例属性,它们是每个实例对象所拥有的。所以将name和age放在构造函数中。前一篇文章已经讨论过,new关键字生成一个对象,并且使用new后面的函数来初始化这个对象。所以name和id这两个实例属性已经通过this.name = name 和this.age = age这两行代码加在了实例对象上面了。
Person.YOUNG是类属性,它是由Person类所拥有的。isAdult中通过与它比较来判断一个Person是否为成年人。如果YOUNG的值改变了,那么所有isAdult的行为也会发生变化。
sayHello,isAdult和grow是实例方法。通过对象进行调用,实例方法中经常会带有this关键字,用来指代调用方法的对象。前一篇文章已经讨论过,通过new关键字的对象以构造函数的prototype属性为原型。所以根据原型链的概念,所有对Person类的对象都能调用这些方法。对象可以通过调用grow方法来增长其age的值,grow方法的this指代的是调用它的对象。
那么就能使用这个类了:
var p = new Person("Jack", 17);
p.sayHello();//Hello!I am Jack
p.isAdult();//false
p.grow();
p.isAdult();//true
定义子类
这里介绍定义子类的基本方法。定义子类的关键是,将基类(父类)的prototype属性作为子类的prototype属性的原型。这样就能构成一个原型链:实例->子类.prototype->父类.prototype。那么根据原型链的概念,就能通过实例对象访问父类定义的方法。同样,子类也可以覆盖父类中的方法。
在传统面向对象编程语言中,子类(基类)在构造函数中会调用父类的构造函数。子类在覆盖父类方法中也能调用父类的方法。因为在定义子类时,我们往往希望对父类的行为进行修改或补充,而不一定是完全替换它们。
//define a sub class
var Student = function(major,name,age){
this.major = major;
Person.prototype.constructor.call(this,name,age);
};
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
Student.baseClass = Person;
//override the sayHello method
Student.prototype.sayHello = function(){
//call the method in the base class
Student.baseClass.prototype.sayHello.call(this);
console.log("I am a " + this.major + " student!");
};
//add a method
Student.prototype.doHomework = function(){
console.log("I am doing " + this.major + " homework!");
};
Student类是Person类的子类。它的每个实例对象除了拥有name和age之外还拥有一个major属性,用来表示每个student的专业。因为Person类的构造函数已经对name和age进行初始化了,所以在Student类的构造函数中可以调用其父类的构造函数(第4行)。
为了让Student的实例也能访问Person类的实例方法,就要将Person.prototype作为Student.prototype的原型。这样就构成了原型链:实例->Student.prototype->Person.prototype。代码的第6行实现了这一点。需要补充的是:Student.prototype = new Person() 同样可以将Person.prototype作为Student.prototype的原型,但是此时Student.prototype却拥有了两个实例属性name和age,而这两个实例属性应该是实例所拥有而非类的prototype拥有。所以在这里使用Object.create(Person.prototype)比较好。(具体使用哪种方法要根据实现类的步骤决定)
第7行的作用是将Student类的构造函数纠正为Student.
第8行的作用是将Student类的基类(父类)赋值为Person,方便之后重定义父类方法时调用。
Student类重定义了父类中的sayHello方法,不仅说出了自己的name而且说出了自己的major是什么。因为sayHello中只是补充了说出major的行为,所以调用了父类的方法。
最后Student类增加了一个doHomework的方法(因为学生都得做作业)。
这样就能使用这个类了:
var s = new Student("Computer Science","Mike",17);
s.sayHello();//Hello!I am Mike
//I am a Computer Science student!
s.isAdult();//false
s.grow();
s.isAdult(); //true
s.doHomework();//I am doing Computer Science homework!
面向对象编程的作用是:封装,继承和多态。我会在相关日志中不断从这三个角度更新日志。
参考文章:
1)《JavaScript The Definitive Guide》第九章
2)CoolShell:http://coolshell.cn/articles/6441.html
3)MDN:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript
JavaScript 面向对象编程(三)如何写类和子类的更多相关文章
- JavaScript面向对象编程(2)-- 类的定义
最近这一段时间事情太多了,没有时间再继续写,幸好这两天有点小闲,先小写一下JavaScript中面向对象一中推荐的方法.本文承接上一篇JavaScript面向对象编程(1) -- 基础. 上篇说过,J ...
- JavaScript面向对象编程(二)构造函数和类
new关键字和构造函数 在文章JavaScript面向对象编程(一)原型与继承中讨论啦JavaScript中原型的概念,并且提到了new关键字和构造函数.利用new关键字构造对象的实例代码如下: // ...
- (三)Javascript面向对象编程:非构造函数的继承
Javascript面向对象编程:非构造函数的继承 这个系列的第一部分介绍了"封装",第二部分介绍了使用构造函数实现"继承". 今天是最后一个部分,介绍不使 ...
- Javascript面向对象编程(三):非构造函数的继承(对象的深拷贝与浅拷贝)
Javascript面向对象编程(三):非构造函数的继承 作者: 阮一峰 日期: 2010年5月24日 这个系列的第一部分介绍了"封装",第二部分介绍了使用构造函数实现&quo ...
- JavaScript 面向对象编程(三):非构造函数对象的继承
JavaScript 面向对象编程(三):非构造函数对象的继承 一.什么是"非构造函数"的继承? 比如,现在有一个对象,叫做"中国人". var Chinese ...
- 【转】Javascript 面向对象编程(一):封装
原文链接:http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html Javascript ...
- Javascript 面向对象编程(一):封装 by 阮一峰
<Javascript高级程序设计(第二版)>(Professional JavaScript for Web Developers, 2nd Edition) 它们都是非常优秀的Java ...
- 转:javascript面向对象编程
作者: 阮一峰 日期: 2010年5月17日 学习Javascript,最难的地方是什么? 我觉得,Object(对象)最难.因为Javascript的Object模型很独特,和其他语言都不一样,初学 ...
- 探讨javascript面向对象编程
(个人blog迁移文章.) 前言: 下面将探讨javascript面向对象编程的知识. 请不要刻意把javascript想成面向对象编程是理所当然的. javascript里面,对象思想不可少,但是不 ...
随机推荐
- Intel 的面试经历中国研究院
那么今天写Intel 的面试经历中国研究院.Intel我采访了面试题比较简单的一. 第一次是在大约下午五时三十, 我正在食堂和好几个基友吃20元巨资买的清蒸草鱼.正在吐沫星子四处飞溅的时候.一个010 ...
- Android 平台 HTTP网速測试 案例 API 分析
作者 : 万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/25996817 工信部规定的网速測试标准 : 除普通网页測速 ...
- JS中Array数组的三大属性用法
原文:JS中Array数组的三大属性用法 Array数组主要有3大属性,它们分别是length属性.prototype属性和constructor属性. JS操作Array数组的方法及属性 本文总结了 ...
- Java_POI之MS-Excel2003(扩展名.xls)升级至MS-Excel2007及以上版本(扩展名.xlsx)技术过程概要
Java_POI之MS-Excel2003(扩展名.xls)升级至MS-Excel2007及以上版本(扩展名.xlsx)技术过程概要 作者:Eric.Zhang(花名:穿越者7号) 日期:2015年1 ...
- IE中的事件对象
IE中的事件对象 1)type属性 用于获取事件类型 2)srcElement属性 用于获取事件的目标 3)cancelBubble属性 用于阻止事件冒泡 设置为true表示阻止事件冒泡 设置为fa ...
- ASP.NET4.0新特性
原文:ASP.NET4.0新特性 在以前试用VS2010的时候已经关注到它在Web开发支持上的一些变化了,为此我还专门做了一个ppt,当初是计划在4月12日那天讲的,结果因为莫名其妙的原因导致没有语音 ...
- Java阅读word程序说明文件
完成office文件操作可以帮助apache.poi包(我用poi-3.10-FINAL),导入对应的jar包(最好所有导入) 以下的程序演示了一些操作word的过程,具体的函数功能能够查看此包的官方 ...
- Spring之SpringMVC的MethodNameResolver(源码)分析
前言 在介绍SpringMVC 的Controller的具体实现中,我们讲到了MultiActionController.在获取处理请求对于的方法的时候我们用到了下面的代码,来自于MultiActi ...
- Spring IOC之基于JAVA的配置
基础内容:@Bean 和 @Configuration 在Spring中新的支持java配置的核心组件是 @Configuration注解的类和@Bean注解的方法. @Bean注解被用于表明一个方法 ...
- C++在struct与class差异
在C++中,既能够用structkeyword进行类的定义,也能够用classkeyword进行类的定义,那么这两者究竟有什么差别呢? 唯一的一点差别是:struct和class的默认訪问权限不一样. ...