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里面,对象思想不可少,但是不 ...
随机推荐
- 网站静态化处理—web前端优化—中(12)
网站静态化处理—web前端优化—中(12) Web前端很多优化原则都是从如何提升网络通讯效率的角度提出的,但是这些原则使用的时候还是有很多陷阱在里面,如果我们不能深入理解这些优化原则背后所隐藏的技术原 ...
- mono for android 学习记录
C#开发Android应用实战(全 扫描 中文版) 学习记录: 拖完控件后,不要急着按F5,需要重新生成,才能自动修改 Resource.Designer.cs 文件 1. Activity 是基于a ...
- MS SQL Server递归查询
原文:MS SQL Server递归查询 刚才在论坛上看到网友一个要求.参考如下,Insus.NET分析一下,可以使用MS SQL Server的递归查询,得到结果.准备一张表: 根据网友提供的数据, ...
- Hibernat之关系的处理一对多/多对一
第一步:编写两个pojo,比如一个学生表一个班级表 这里使用注解. 需要 班级表: package com.qcf.pox; import java.util.HashSet; import jav ...
- addEventListener 与attachEvent
第一:简单的通用方法(IE && FF) window.onload = function(){ var oDiv = document.getElementById("J_ ...
- 【Unity Shaders】Mobile Shader Adjustment —— 为手机定制Shader
本系列主要參考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同一时候会加上一点个人理解或拓展. 这里是本书全部的插图.这里是本书所需的代码和 ...
- .NET开源项目 TOP 25
.NET开源项目 TOP 25 如果知道.NET项目在开源中国的git上所占的比重只有5%的话,为什么这个<2014年国人开发的最热门的开源软件TOP 100>榜中.NET项目那么少就是情 ...
- SQL点滴33—SQL中的字符串操作
原文:SQL点滴33-SQL中的字符串操作 计算字符串长度len()用来计算字符串的长度 select sname ,len(sname) from student 字符串转换为大.小写lower() ...
- jQuery EasyUI API - Grid - DataGrid [原创汉化官方API]
最近在学习jQuery EasyUI,发现中文的文档好少,部分文档不错但它是鸟语的,为了大家也为了自己学习吧,汉化做一下笔记. 有没有说清楚的,或者翻译不正确的地方还请大家谅解指出.. 由于工作时间原 ...
- Elegant Box主题wpdb::prepare() 报错[已解决]
整理书签,发现个网页,是解决Elegant Box主题与新版Wordpress3.5主题不兼容的(3.5改了一个函数的参数个数所致).记得当时使用NeoEase出的主题的时候两次遇到这个问题,费了点功 ...