JS 类继承和原型继承区别

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS 类继承和原型继承区别相关的知识,希望对你有一定的参考价值。

最近研究JS 的继承问题,知道常用的两种继承方式,一是类继承,而是原型继承。看了一些文章,但是有点混淆,发型他们很相似的呢,想知道两者的区别到底是怎么样的,求指教。
原型继承方式:
function parent();
parent.prototype.Pname='Parent';
function child()
child.prototype=new parent(); //将子类的原型指向父类
child.prototype.Cname='child';
这样就实现了原型继承。
类继承方式:

function parent2(sparam)
this.param=sparam;
this.getParam=function()
return this.param;

;

function child2(cparam,cname)
parent2.call(this,cparam); //调用父类构造函数
this.name=cname;

child2.prototype=new parent2('param'); //继承父类
child2.prototype.getName=function()
return this.name;

这样完成类继承。

看完就觉得迷糊,感觉是类似的啊,没有啥本质的区别,只是一个带参数,一个不能带参数。请高手指点指点。

类式继承就像java的继承一样,思想也比较简单:在子类型构造函数的内部调用超类型构造函数。

原型式继承是借助已有的对象创建新的对象,将子类的原型指向父类,就相当于加入了父类这条原型链

而你的 下面这段代码不是严格意义上的类式继承,按照Nicholas C.Zakas的说法,这个应该叫做组合式继承。它调用了两次parent2()。第一次是 child2.prototype=new parent2('param'); child2就会得到两个属性param,getParam(),他们都是parent2的属性,但是他们在child2的原型中。第二次是parent2.call(this,cparam); 这次又在新对象上创建了实例属性param,getParam()。于是,这两个属性就屏蔽了原型中的两个同名属性。这有什么好处呢,就是你在构建一个child3时也继承parent2()的属性,还可以定义自己的属性。与此同时他长的就和他兄弟不同了,但又有一样的“血统(使用父类的方法)”。

纯手打,欢迎继续讨论追问

嗯 第二种我说的类继承确实不严格,但看到不少博客把这种继承叫做类继承。我查看了一些教材,很少有说类继承的,也多是组合继承,请问您有见过严格的类继承吗?应该是什么样的?

追答

严格的类继承不是很常见,一般都是组合着用。看下例:

function Super()
    this.colors=["red","blue"];


function Sub()
    Super.call(this);

这就是类式继承,这个有一个缺点就是   方法在构造函数内创建,函数的复用就无从谈起了,而且还有一个问题,就是在超类原型中定义的方法对子类是不可见的。


还有就是子类会复制父类的属性,如下:

var a=new Sub();
a.colors.push("black");
console.log(a.colors);//----->   "red,blue,black"

var b=new Sub();
console.log(b.colors);//----->   "red,blue"



其实最常用的还是组合继承,至于用什么继承模式,完全不用纠结,这要看具体使用环境

参考技术A javascript函数不会对传参情况进行检测,所以这个不是重点。借用父类构造函数,可以获得父类构造函数里面的相同属性和方法。例如第二种,子类实例拥有param、getParam两个成员,而第一种是没有的。追问

那这样说来,类继承中 child2.prototype=new parent2('param'); 这句是完全可以不用的嘛,直接通过call得到了父类的属性和方法,可以不再需要改变子类的原型,对吧?
还有其他什么区别吗?

追答

如果不用的话继承不到父类的原型

参考技术B 1.JS类式继承:
/* -- 类式继承 -- */
//先声明一个超类
function Person(name)
this.name = name;

//给这个超类的原型对象上添加方法 getName
Person.prototype.getName = function()
return this.name;

//实例化这个超
var a = new Person('Darren1')
console.log(a.getName());//Darren1
//再声明类
function Programmer(name, sex)
//这个类中要调用超类Person的构造函数,并将参数name传给它
Person.call(this, name);
this.sex = sex;

//这个子类的原型对象等于超类的实例
Programmer.prototype = new Person();
//因为子类的原型对象等于超类的实例,所以prototype.constructor这个方法也等于超类构造函数,你可以自己测试一下,如果没这一步,console.log(Programmer.prototype.constructor这个是Person超类的引用,所以要从新赋值为自己本身
console.log(Programmer.prototype.constructor);
/*function Person(name)
this.name = name;
*/
Programmer.prototype.constructor = Programmer;
console.log(Programmer.prototype.constructor);
/*function Programmer(name, sex)
Person.call(this, name);
this.sex = sex;

*/
//子类本身添加了getSex 方法
Programmer.prototype.getSex = function()
return this.sex;

//实例化这个子类
var _m = new Programmer('Darren2', 'male');
//自身的方法
console.log(_m.getSex());//male
//继承超类的方法
console.log(_m.getName());//Darren2

2.JS原型继承:
/* -- 原型式继承 -- */
//clone()函数用来创建新的类Person对象
var clone = function(obj)
4
var _f = function() ;
//这句是原型式继承最核心的地方,函数的原型对象为对象字面量
_f.prototype = obj;
return new _f;

//先声明一个对象字面量
var Person =
name: 'Darren',
getName: function()
return this.name;


//不需要定义一个Person的子类,只要执行一次克隆即可
var Programmer = clone(Person);
//可以直接获得Person提供的默认值,也可以添加或者修改属性和方法
alert(Programmer.getName())
Programmer.name = 'Darren2'
alert(Programmer.getName())
//声明子类,执行一次克隆即可
var Someone = clone(Programmer);

以上是关于JS 类继承和原型继承区别的主要内容,如果未能解决你的问题,请参考以下文章

JS类的创建与继承

JS 类继承 原型继承

JS面向对象组件 -- 继承的其他方式(类式继承原型继承)

js里面的对象继承几种方法

JS原型继承和类式继承

js继承