javascript的继承方式

javascript的继承同对象的创建一样有许多的方式,每种方式都有自己的的特点。

一、原型链继承
function SuperType() {
    this.property = true;
}
SuperType.prototype.getSuperValue = function() {
    return this.property;
};
function SubType() {
    this.subproperty = false;
}
//继承SuperType
SubType.prototype = new SuperType(); //重写了SuberType的原型
SubType.prototype.getSubValue = function() {
    return this.subproperty;
};
var instance = new SubType();
alert(instance.getSuperValue()); //true

SubType继承SuperType的继承,是通过重写SubType原型来实现的,这里不同与原型模式以字面量形式重写原型和改变constructor属性的指向,这里是通过改变SubType原型的指向,即指向SuperType的原型。
原型链继承有它的缺点,如同原型模式创建对象一样,遇到引用类型值,通过一个实例化对象改变引用类型值,其他的实例化对象访问这个引用对象的值时,是改变后的。这有时会与所期望不一致。
同时也要注意,为SubType原型添加方法需要放在重写之后,否则会将添加的方法覆盖。而且不能使用字面量方式重写SubType原型,这样会重写原型链,而无法继承SuperType

二、借用构造函数继承

通过使用call(), apply()函数在后面创建的对象上执行构造函数

function SuperType() {
    this.colors = ["red", "blue", "green"];
}
function SubType() {
    SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
var instance2 = new SubType();
alert(instance2.colors); //"red,blue,green"

实例化对象通过call()得到了SuperType属性的副本,从而实现继承
这样的继承方式都是在构造函数里定义的,函数复用的可能大大减少。

三、组合继承
function SuperType(name) {
    this.name = name;
    this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
    alert(this.name);
};
function SubType(name,age) {
    SuperType.call(this, name);
    this.age = age;
}
//继承方法
SubType.prototype = new SuperType(); //第二次调用SuperType(name)
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function() {
    alert(this.age);
};
var instance1 = new SubType("Nicholas", 29); //第一次调用SuperType(name)
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
instance1.sayName(); //"Nicholas"
instance1.sayAge(); //29
var instance2 = new SubType("Greg", 27);
alert(instance2.colors); //"red,blue,green"
instance2.sayName(); //"Greg"
instance2.sayAge(); //27

通过call得到SuperType的属性的副本(那些需要共享的内容),改变其值,也不会影响其他实例化对象的副本,这样便同时拥有了原型链继承和借用构造函数继承两种方式的优点,但是组合继承因为call()函数的存在,始终会调用两次SuperType的构造函数。

四、原型式继承

利用一个空对象作为中介

function object(o) {
    function F(){} //临时的构造函数
    F.prototype = o;
    return new F()
}
var person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"

object()函数对person基本数据的复制,即“浅复制“。这样做就person成为新对象anotherPerson和yetAnotherPerson的原型,同时person中有一个引用类型数据。也就造成修改新对象同时,person也会被修改。是否是你需要的,得看你自己的需求。

五、寄生组合式继承

寄生组合式继承:通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。

function object(o) {
    function F(){}
    F.prototype = o;
    return new F();
}
function inheritPrototype(subType, superType) {
    var prototype = object(superType.prototype);
    prototype.constructor = subType;
    subType.prototype = prototype;
}
function SuperType(name) {
    this.name = name;
    this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
    alert(this.name);
};
function SubType(name, age) {
    SuperType.call(this, name);
    this.age = age;
}
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function() {
    alert(this.age);
};
var instance = new SubType("Nicholas", 29);
instance.sayAge();

参考Javascript面向对象编程(二):构造函数的继承的利用空对象进行继承


总结

函数即是对象,创建的每一个函数都有一个prototype属性,即原型属性。这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以有特定类型的所有实例共享的属性和方法。意思是:prototype就是通过调用构造函数而创建的那个对象实例的原型对象。可以让所有对象实例共享它所包含的属性和方法。所以在继承中,一定要注意原型链的存在,重写原型链,则要将原型链纠正,保证原型链不被破坏,但同时也要看到原型链上不应有有引用类型的数据作为共享。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值