Summary

  • You cause a class to inherit using ChildClassName.prototype = new ParentClass();.
  • You need to remember to reset the constructor property for the class using ChildClassName.prototype.constructor=ChildClassName.
  • You can call ancestor class methods which your child class has overridden using the Function.call() method.
  • Javascript does not support protected methods.

Example

To jump right into it, following is a sample showing inheritance between two classes:

function Mammal(name){
this.name=name;
this.offspring=[];
}
Mammal.prototype.haveABaby=function(){
var newBaby=new Mammal("Baby "+this.name);
this.offspring.push(newBaby);
return newBaby;
}
Mammal.prototype.toString=function(){
return '[Mammal "'+this.name+'"]';
} Cat.prototype = new Mammal(); // Here's where the inheritance occurs
Cat.prototype.constructor=Cat; // Otherwise instances of Cat would have a constructor of Mammal
function Cat(name){
this.name=name;
}
Cat.prototype.toString=function(){
return '[Cat "'+this.name+'"]';
} var someAnimal = new Mammal('Mr. Biggles');
var myPet = new Cat('Felix');
alert('someAnimal is '+someAnimal); // results in 'someAnimal is [Mammal "Mr. Biggles"]'
alert('myPet is '+myPet); // results in 'myPet is [Cat "Felix"]' myPet.haveABaby(); // calls a method inherited from Mammal
alert(myPet.offspring.length); // shows that the cat has one baby now
alert(myPet.offspring[0]); // results in '[Mammal "Baby Felix"]'

The someAnimal & myPet above inner logical struct:

Using the .constructor property

Look at the last line in the above example. The baby of a Cat should be a Cat, right? While the haveABaby() method worked, that method specifically asks to create a new Mammal. While we could make a new haveABaby() method for the Cat subclass like this.offspring.push(new Cat("Baby "+this.name)), it would be better to have the ancestor class make an object of the correct type.

Every object instance in JS has a property named constructor that points to its parent class. For example, someAnimal.constructor==Mammmal is true. Armed with this knowledge, we can remake the haveABaby() method like this:

Mammal.prototype.haveABaby=function(){
var newBaby=new this.constructor("Baby "+this.name);
this.offspring.push(newBaby);
return newBaby;
}
...
myPet.haveABaby(); // Same as before: calls the method inherited from Mammal
alert(myPet.offspring[0]); // Now results in '[Cat "Baby Felix"]'

Calling 'super' methods

Let's extend the example now so that when baby kittens are created, they 'mew' right after being born. To do this, we want to write our own customCat.prototype.haveABaby() method, which is able to call the original Mammal.prototype.haveABaby() method:

Cat.prototype.haveABaby=function(){
Mammal.prototype.haveABaby.call(this);
alert("mew!");
}

The above may look a little bit bizarre. Javascript does not have any sort of 'super' property, which would point to its parent class. Instead, you use thecall() method of a Function object, which allows you to run a function using a different object as context for it.

Making your own 'super' property

Rather than having to know that Cat inherits from Mammal, and having to type in Mammal.prototype each time you wanted to call an ancestor method, wouldn't it be nice to have your own property of the cat pointing to its ancestor class? Those familiar with other OOP languages may be tempted to call this property 'super', but JS reserves this word for future use. The word 'parent', while used in some DOM items, is free for the JS language itself, so let's call it parentin this example:

Cat.prototype = new Mammal();
Cat.prototype.constructor=Cat;
Cat.prototype.parent = Mammal.prototype;
...
Cat.prototype.haveABaby=function(){
var theKitten = this.parent.haveABaby.call(this);
alert("mew!");
return theKitten;
}

Spoofing pure virtual classes

Some OOP languages have the concept of a pure virtual class...one which cannot be instantiated itself, but only inherited from. For example, you might have aLivingThing class which Mammal inherited from, but you didn't want someone to be able to make a LivingThing without specifying what type of thing it was. You can do this in JS by making the virtual class an object instead of a function.

The following example shows how this could be used to simulate a pure virtual ancestor:

LivingThing = {
beBorn : function(){
this.alive=true;
}
}
...
Mammal.prototype = LivingThing;
Mammal.prototype.parent = LivingThing; //Note: not 'LivingThing.prototype'
Mammal.prototype.haveABaby=function(){
this.parent.beBorn.call(this);
var newBaby=new this.constructor("Baby "+this.name);
this.offspring.push(newBaby);
return newBaby;
}

With the above, doing something like var spirit = new LivingThing() would result in an error, since LivingThing is not a function, and hence can't be used as a constructor.

Convenient Inheritance

Rather than writing 3 lines every time you want to inherit one class from another, it's convenient to extend the Function object to do it for you:

Function.prototype.inheritsFrom = function( parentClassOrObject ){
if ( parentClassOrObject.constructor == Function )
{
//Normal Inheritance
this.prototype = new parentClassOrObject;
this.prototype.constructor = this;
this.prototype.parent = parentClassOrObject.prototype;
}
else
{
//Pure Virtual Inheritance
this.prototype = parentClassOrObject;
this.prototype.constructor = this;
this.prototype.parent = parentClassOrObject;
}
return this;
}
//
//
LivingThing = {
beBorn : function(){
this.alive = true;
}
}
//
//
function Mammal(name){
this.name=name;
this.offspring=[];
}
Mammal.inheritsFrom( LivingThing );
Mammal.prototype.haveABaby=function(){
this.parent.beBorn.call(this);
var newBaby = new this.constructor( "Baby " + this.name );
this.offspring.push(newBaby);
return newBaby;
}
//
//
function Cat( name ){
this.name=name;
}
Cat.inheritsFrom( Mammal );
Cat.prototype.haveABaby=function(){
var theKitten = this.parent.haveABaby.call(this);
alert("mew!");
return theKitten;
}
Cat.prototype.toString=function(){
return '[Cat "'+this.name+'"]';
}
//
//
var felix = new Cat( "Felix" );
var kitten = felix.haveABaby( ); // mew!
alert( kitten ); // [Cat "Baby Felix"]

Just make sure you call this method immediately after your constructor, before you extend the prototype for the object.

Protected methods?

Some OOP languages have the concept of 'protected' methods—methods that exist in a parent or ancestor class that can only be called by descendants of the object (on each other), but not by external objects. These are not supported in JS. If you need such, you will have to write your own framework, ensuring that each class has a 'parent' or some such property, and walking up the tree to find ancestors and checking whether or not the calling object is the same type. Doable, but not enjoyable.

Quote From:

OOP in JS, Part 2 : Inheritance

Reference:

Understanding JavaScript Function Invocation and "this"

OOP in JS - Inheritance的更多相关文章

  1. OOP in JS Public/Private Variables and Methods

    Summary private variables are declared with the 'var' keyword inside the object, and can only be acc ...

  2. js inheritance all in one

    js inheritance all in one prototype & proto constructor Object.definepropety Object.create() js ...

  3. JS--我发现,原来你是这样的JS:面向对象编程OOP[3]--(JS继承)

    一.面向对象编程(继承) 这篇博客是面向对象编程的第三篇,JS继承.继承顾名思义,就是获取父辈的各种"财产"(属性和方法). 怎么实现继承? 我们的JavaScript比较特别了, ...

  4. JS OOP -04 JS中的公有成员,私有成员和静态成员

    JS中的公有成员,私有成员和静态成员 a.实现类的公有成员 b.实现类的私有成员 c.实现类的静态成员 a.实现类的公有成员 之前定义的任何类型成员都属于公有成员的范畴,该类的任何实例都对外公开这些属 ...

  5. JS OOP -03 JS类的实现

    JS类的实现: a.理解类的实现机制 b.使用prototype对象定义类成员 c.一种JS类的设计模式 a.理解类的实现机制 在JS中可以使用function关键字来定义一个类. 添加类的成员,在函 ...

  6. 小结JS中的OOP(上)

    前言:大家都知道,OOP有三大特性:封装,继承,多态.下面是自己对这三个特性的理解: 封装:把属性与方法整合到某种数据类型中.目的是让类的使用者按类的编写者的意愿去使用类.在封装过程中会一般会做两件事 ...

  7. JS面向对象思想(OOP)

    直接看js好了,模拟创建一个奥运会 function 奥运会Class(主题) { // 删除主题 // delete this.主题; this.主题 = 主题; this.开幕时间; this.闭 ...

  8. 三言两语之js面向对象初探1

    http://www.cnblogs.com/54td/p/5580994.htm    先是有了这个比较简短但是内容比较丰盈的上篇,现在时间比较充沛,所以详细写来.搞前端的同学经常被其他程序员bs, ...

  9. 关于JS APP

    多屏screen, JS如何路由,如何换页,导航.通过JS来实现. 当前页面的逻辑通过JS来实现.HTML DOM, Event, Widget. 核心在于function. JS 不仅仅是DOM, ...

随机推荐

  1. 如何在Ubuntu 11.10上连接L2TP VPN

    要在家继续项目的开发,但架设的GitLab只能校内访问,更悲催的是学校架设的SSL VPN不支持Linux,好在想起学校以前架设的L2TP VPN,应该可以支持Linux,于是便一通谷歌百度,然而发现 ...

  2. JS左侧菜单-04

    <script language="javascript" type="text/javascript"> function HideShow() ...

  3. 关于Update语句的锁

    关于Update语句的锁 环境:MSSQL2005,在Read Committed级别 语句A:begin tranUpdate Table Set f1='xxx' where f2='ttt'  ...

  4. MFC注册表操作

    注册表简介 有时程序中要存些设置信息,一个方法就是创建一些普通的txt或xml文件,然后保存进去就行了.另一办法就是保存到注册表里.注册表是由windows维护的一个小数据库.里面也会保存window ...

  5. 3364 Lanterns (异或方程组高斯消元)

    基本思路.首先构造一个n*(m+1)的矩阵,同时标记一个行数row,row从零开始,然后找出每一列第一个非零的数,和第row行互换, 然后对row到n行,异或运算.最终的结果为2^(m-row) #i ...

  6. 创建和使用SQL Server SSAS本地多维数据集

    Microsoft SQL Server SSAS的本地多维数据集(即Local Cube,也叫脱机多维数据集)和本地挖掘模型(Local Mining Models)允许在客户端机器上脱机执行离线分 ...

  7. 【Android LibGDX游戏引擎开发教程】第07期:中文字体的显示和绘制(上)

    在字体的显示和绘制中,Libgdx的作者(Mario Zechner,美国人)给我们提供了一个非常好用的工具 ——Hiero,那么下面就来看看它具体的使用方法. 一.Hiero工具的使用 1.Hier ...

  8. Android 开发环境 —— Eclipse 启动时报错:Error when loading the SDK

    简述: Eclipse 启动时报错:Error when loading the SDK 错误信息: Error when loading the SDK: Error: Error parsing  ...

  9. Java入门第二季第一章类和对象知识点

    Java 中的 static 使用之静态方法 1. 静态方法中可以直接调用同类中的静态成员,但不能直接调用非静态成员.如: 如果希望在静态方法中调用非静态变量,可以通过创建类的对象,然后通过对象来访问 ...

  10. hdu1041

    #include <iostream> #include <string> using namespace std; const int SIZE = 1001; const ...