您的位置:首页 > Web前端 > JavaScript

利用prototype实现JavaScript继承

2012-07-05 13:48 597 查看
本文主要是讲解如何通过prototype实现JavaScript继承,并逐步循序渐进,最终实现一个继承的通用函数。
1.首先我们定义一个父类Father,如下所示:
function Father(){
this.name = "姓名";
this.age = "20";
this.setName = function(str){this.name=str};
this.getName = function(){return this.name;};
}
Father.prototype.setAge = function(age){this.age = age;};
Father.prototype.getAge = function(){return this.age;};
console.log(new Father());运行结果如下:
Fatherage: "20"
getName: function (){return this.name;}
name: "姓名"
setName: function (str){this.name=str}
__proto__: Fatherconstructor: function Father(){
getAge: function (){return this.age;}
setAge: function (age){this.age = age;}
__proto__: Object

可以看到Father具有age、name两个属性以及getName、setName、getAge、setAge四个方法,但是要注意的是setAge、getAge方法是放在Father.prototype中的,prototype中的方法是公共方法,也就是说在创建新的实例时,prototype中的内容不会随着新实例的创建而占用更多的内存,所以公共方法最好放到prototype中。而实例中的setName与getName方法是在实例中的,每当新实例创建时,每个新实例都会额外占用内存来存储这两个方法。

2.使用call(context,para1...)尝试实现继承
代码如下:
function Sun1(){
Father.call(this);
}
console.log(new Sun1())
运行结果如下:

Sun1age: "20"
getName: function (){return this.name;}
name: "姓名"
setName: function (str){this.name=str}
__proto__: Sun1constructor: function Sun1(){
__proto__: Object

由上可知,在子类的构造函数中通过调用Father.call(this)只能使得子类具有父类构造器中写明的属性与方法,但是不能继承父类的prototype中的内容getAge与setAge。

3.尝试使用apply(context,arguments)尝试实现继承
代码如下:
function Sun2(){
Father.apply(this,arguments);
}
console.log(new Sun2());
运行结果如下:

Sun2age: "20"
getName: function (){return this.name;}
name: "姓名"
setName: function (str){this.name=str}
__proto__: Sun2constructor: function Sun2(){
__proto__: Object

由上可知,在子类的构造函数中通过调用Father.apply(this,arguments)也只能使得子类具有父类构造器中写明的属性与方法,但是不能继承父类的prototype中的内容getAge与setAge。

4.通过更改prototype实现继承
代码如下:
function Sun3(){}
Sun3.prototype = new Father();
Sun3.prototype.constructor = Sun3;
console.log(new Sun3());
运行结果如下:

Sun3__proto__: Fatherage: "20"
constructor: function Sun3(){}
getName: function (){return this.name;}
name: "姓名"
setName: function (str){this.name=str}
__proto__: Fatherconstructor: function Father(){
getAge: function (){return this.age;}
setAge: function (age){this.age = age;}
__proto__: Object

由上可知,我们将子类的prototype属性的值设置为父类的一个实例,就可以使得子类继承了父类的所有属性与方法,需要注意的是,代码Sun3.prototype.constructor = Sun3的意思是将子类的prototype.constructor重新设置为子类的构造器函数。任何一个prototype对象都有一个constructor属性,指向它的构造函数。也就是说,Sun3.prototype 这个对象的constructor属性,是指向Sun3的。代码Sun3.prototype = new Father()删除了这个Sun3.prototype对象原来的值,所以新的prototype对象没有constructor属性,所以我们必须手动加上去,否则后面的"继承链"会出问题。这一点很重要,要切记。

5.继承函数的实现
既然我们知道了如何通过prototype来实现继承,那么我们就可以将该实现封装成一个函数,使得代码可重用,代码如下:
function inherit(child,parent){
child.prototype = new parent();
child.prototype.constructor = child;
}
function Sun4(){}
inherit(Sun4,Father);
console.log(new Sun4());运行结果如下:

__proto__: Fatherage: "20"
constructor: function Sun4(){}
getName: function (){return this.name;}
name: "姓名"
setName: function (str){this.name=str}
__proto__: Fatherconstructor: function Father(){
getAge: function (){return this.age;}
setAge: function (age){this.age = age;}
__proto__: Object

我们将继承封装成inherit函数,要想实现两个类的继承关系时,把这两个类作为参数传递进去即可。

6.面向对象的通用继承的实现
虽然上文已经通过inherit函数实现了继承函数,但是在使用时每次都要把父子两个类传递进去,还不够面向对象,为了更好的模拟面向对象的特性,我们再进一步进行改进,代码如下:
Function.prototype.method = function(funcName,func){
this.prototype[funcName] = func;
};

Function.prototype.inherit = function(parent){
this.prototype = new parent();
this.prototype.constructor = this;
};

function Sun5(){}
Sun5.inherit(Father);
console.log(new Sun5());
运行结果如下:

Sun5__proto__: Fatherage: "20"
constructor: function Sun5(){}
getName: function (){return this.name;}
name: "姓名"
setName: function (str){this.name=str}
__proto__: Fatherconstructor: function Father(){
getAge: function (){return this.age;}
setAge: function (age){this.age = age;}
__proto__: Object

Function.prototype.method:此函数是为构造器的prototype附加函数的简单方式。这一特殊的子句能够工作是因为所有的构造器都是函数,故能获得新的方法"method"。 
Function.prototype.inherit:这一函数能用来实现单父继承。由于inherit方法是在Function的原型中的,所以使得所有的子类都能有原生的使用该inherit方法,只需要传递父类的构造函数即可。
注意:在inherit函数中调用parent 的构造函数,没有给它传递参数。这在原型链中是标准做法。要确保构造函数没有任何参数。
如果父类的构造函数中有参数,那该怎么办呢?可以这样实现,代码如下:
function Father(name,age){
this.name = name;
this.age = age;
this.setName = function(str){this.name=str};
this.getName = function(){return this.name;};
}
Father.prototype.setAge = function(age){this.age = age;};
Father.prototype.getAge = function(){return this.age;};
console.log(new Father());

Function.prototype.method = function(funcName,func){
this.prototype[funcName] = func;
};
Function.prototype.inherit = function(parent){
this.prototype = new parent();
this.prototype.constructor = this;
};

function Sun6(name,age){
Father.call(this,name,age);
}
Sun6.inherit(Father);
console.log(new Sun6("姓名",20));
运行结果如下:

Sun6age: 20
getName: function (){return this.name;}
name: "姓名"
setName: function (str){this.name=str}
__proto__: Fatherage: undefined
constructor: function Sun6(name,age){
getName: function (){return this.name;}
name: undefined
setName: function (str){this.name=str}
__proto__: Father

这里通过call与prototype的共同使用才实现了继承。
参考:
http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html

http://www.w3school.com.cn/js/pro_js_inheritance_implementing.asp
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: