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 面向对象编程(三)如何写类和子类的更多相关文章

  1. JavaScript面向对象编程(2)-- 类的定义

    最近这一段时间事情太多了,没有时间再继续写,幸好这两天有点小闲,先小写一下JavaScript中面向对象一中推荐的方法.本文承接上一篇JavaScript面向对象编程(1) -- 基础. 上篇说过,J ...

  2. JavaScript面向对象编程(二)构造函数和类

    new关键字和构造函数 在文章JavaScript面向对象编程(一)原型与继承中讨论啦JavaScript中原型的概念,并且提到了new关键字和构造函数.利用new关键字构造对象的实例代码如下: // ...

  3. (三)Javascript面向对象编程:非构造函数的继承

    Javascript面向对象编程:非构造函数的继承   这个系列的第一部分介绍了"封装",第二部分介绍了使用构造函数实现"继承". 今天是最后一个部分,介绍不使 ...

  4. Javascript面向对象编程(三):非构造函数的继承(对象的深拷贝与浅拷贝)

    Javascript面向对象编程(三):非构造函数的继承   作者: 阮一峰 日期: 2010年5月24日 这个系列的第一部分介绍了"封装",第二部分介绍了使用构造函数实现&quo ...

  5. JavaScript 面向对象编程(三):非构造函数对象的继承

    JavaScript 面向对象编程(三):非构造函数对象的继承 一.什么是"非构造函数"的继承? 比如,现在有一个对象,叫做"中国人". var Chinese ...

  6. 【转】Javascript 面向对象编程(一):封装

    原文链接:http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html Javascript ...

  7. Javascript 面向对象编程(一):封装 by 阮一峰

    <Javascript高级程序设计(第二版)>(Professional JavaScript for Web Developers, 2nd Edition) 它们都是非常优秀的Java ...

  8. 转:javascript面向对象编程

    作者: 阮一峰 日期: 2010年5月17日 学习Javascript,最难的地方是什么? 我觉得,Object(对象)最难.因为Javascript的Object模型很独特,和其他语言都不一样,初学 ...

  9. 探讨javascript面向对象编程

    (个人blog迁移文章.) 前言: 下面将探讨javascript面向对象编程的知识. 请不要刻意把javascript想成面向对象编程是理所当然的. javascript里面,对象思想不可少,但是不 ...

随机推荐

  1. 速度 Github

    首先需要了解.git 是版本号的管理工具,为了能够把任意代码托管执照:github 其中一个是. 应用 github 什么不该说的帐户. 那么,申请后,在需求 github 并建立了独特的本地机器上的 ...

  2. Linux常用命令2--用户问题、文件的打包压缩

    Linux常用命令 如何进行用户和群组的创建和更改 [1]groupadd:用于创建新的群组. 语法:groupadd [-option] 用户名:其常用参数有:-g groupadd -g 555 ...

  3. [Asp.net]站点地图SiteMap

    原文:[Asp.net]站点地图SiteMap 引言 在项目中发现使用站点地图的控件,之前没总结过这方面的东西,就写了一个demo测试了一下,这里记录一下,算是总结吧. Web.sitemap < ...

  4. E: 无法获取锁 /var/lib/apt/lists/lock - open (11: Resource temporarily unavailable)解决方法

    /*********************************************************************  * Author  : Samson  * Date   ...

  5. 使用Vs2005打造简单分页浏览器(1)原创

    原文:使用Vs2005打造简单分页浏览器(1)原创 使用Vs2005打造简单分页浏览器(1)原创1引言2功能3实现过程以及关键点4总结5不足之处6其他7 代码下载 1    引言很早就有搞一个浏览器的 ...

  6. POI导出大量数据的简单解决方案(附源码)-Java-POI导出大量数据,导出Excel文件,压缩ZIP(转载自iteye.com)

    说明:我的电脑 2.0CPU 2G内存 能够十秒钟导出 20W 条数据 ,12.8M的excel内容压缩后2.68M 我们知道在POI导出Excel时,数据量大了,很容易导致内存溢出.由于Excel ...

  7. JAVA学习第三十四课 (经常使用对象API)—List集合及其子类特点

    整个集合框架中最经常使用的就是List(列表)和Set(集) 一.List集合 && Set的特点 Collection的子接口: 1.List:有序(存入和取出的顺序一致),元素都有 ...

  8. 安卓WindowManager注入事件如何跳出进程间安全限制

    在分析monkey源码的时候有些背景知识没有搞清楚,比如在看到monkey是使用windowmanager的injectKeyEvent方法注入事件的时候,心里就打了个疙瘩,这种方式不是只能在当前应用 ...

  9. 推荐两个针对github的chrome插件

    作为一只程序猿,在github上找代码.看代码是再正常不过的事情了.这时候有个工具可以方便你翻看代码,想必是极好的. Sourcegraph for GitHub 这个插件允许你像使用IDE那样浏览代 ...

  10. 我看PS求职简历照

    看新闻<大学生求职简历照片不PS 连面试机会都没有>,忍不住也谈些自己的看法. 个人意见,尽量求真,这个求真要有平时努力的保证.长相一般的,知道自己是普通一员,按普通的方式行事就可以.即使 ...