js中的面向对象编程(二)
对象中的继承问题
ECMAScript只支持实现继承,而且其实现继承主要是依靠原型链来实现的
1.原型链
实现原型链的一种基本模式
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperVal = function(){
return this.property
}
function SubType(){
this.subproperty = false;
}
//继承SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubVal = function(){
return this.subproperty;
}
var instance = new SubType();
console.log(instance.getSuperVal()); //true
以上代码定义了两个类型:SuperType和SubType,每个类型都要一个方法和属性。其中SubType通过创建SuperType实例继承了SuperType,并将该实例赋给SubType.prototype实现的。换句话说就是原本存在于SuperType中的属性和方法现在也存在于SubType.prototype中。
1.1确定原型与实例的关系
- 第一种方式是使用instanceof操作符
console.log(instance instanceof Object); //true
console.log(instance instanceof SuperType); //true
console.log(instance instanceof SubType); //true
由原型链的关系,我们可以说instance是Object、SuperType或SubType种任一类型的实例
- 第二种方式是使用isPrototypeOf()方法
console.log(Object.prototype.isPrototypeOf(instance));//true
console.log(SuperType.prototype.isPrototypeOf(instance));//true
console.log(SubType.prototype.isPrototypeOf(instance));//true
只要是 原型链种出现过的原型,都可以说是该原型链所派生的实例的原型
1.2谨慎地定义方法
子类型有时候需要覆盖父类型种的某个方法,或需要添加父类型不存在的某个方法。只要是给原型添加方法的代码一定要放在替换原型的语句之后。
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperVal = function(){
return this.property
}
function SubType(){
this.subproperty = false;
}
// 继承SuperType
SubType.prototype = new SuperType();
// 添加新的方法
SubType.prototype.getSubVal = function(){
return this.subproperty;
}
// 重写父类型中的方法
SubType.protptype.getSuperVal = function(){
return false;
}
var instance = new SubType();
console.log(instance.getSuperVal()); //false
当通过SubType的实例调用getSuperVal()时,调用的是重新定义的那个方法,但当使用SuperType的实例调用getSuperVal()时,还会继续调用原来那个方法
var instance2 = new SuperType();
console.log(instance2.getSuperVal());//false
【注】:当通过原型链实现继承时,不能使用对象字面量创建原型方法,因为这样会重写原型链
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperVal = function(){
return this.property;
}
function SubType(){
this.subproperty = false;
}
//继承SuperType
SubType.prototype = new SuperType();
//使用字面量添加方法,会使上一行继承代码失效
SubType.prototype = {
getSubVal:function(){
return this.subproperty;
},
otherMethod:function(){
return false;
}
}
var instance = new SubType();
console.log(instance.getSuperVal()); //error
1.3原型链的问题
- 包含引用类型值的原型
- 在创建子类的实例时,没有办法在不影响所有对象实例的情况下,给父类型的构造函数传递参数
1.4解决原型链的问题
1.4.1 借助构造函数
在子类型的构造函数中调用父类型的构造函数
function SuperType() {
this.color = ["red", "yellow", "black"];
}
function SubType() {
// 利用call改变this指向实现继承
SuperType.call(this);
}
var instance = new SubType();
instance.color.push("green");
console.log(instance.color); //red,yello,blcak,green
var instance2 = new SubType();
console.log(instance2.color); //red,yellow,black
var instance3 = new SuperType();
console.log(instance3.color); //red,yellow,black
2.继承的定义方式
2.1组合继承
组合继承指的是将原型链和构造方法技术组合在一起
实现思路:使用原型链实现对原型属性和方法的继承,使用构造方法来实现对实例属性的继承
function SuperType(name) {
this.name = name;
this.color = ["red", "yellow", "black"];
}
SuperType.prototype.sayName = function() {
console.log(this.name);
};
function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
}
// 继承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function() {
console.log(this.age);
};
var instance = new SubType("zhangsan", 22);
instance.color.push("green");
instance.sayName(); //zhangsan
instance.sayAge(); //22
console.log(instance.color); // red,yellow,black,green
var instance2 = new SubType("lisi", 23);
instance2.sayName(); //lisi
instance2.sayAge(); //23
console.log(instance2.color); // red,yellow,black
2.2原型式继承
实现思路:原型基于已有的对象创建新对象,而不必因此创建自定义类型
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
var person = {
name: 'zhangsan',
friends: ['lisi', 'wangwu'],
};
var person2 = object(person);
person2.name = 'andy';
person2.friends.push('zhaoliu');
var person3 = object(person);
person3.name = 'Linda';
person3.friends.push('lihua');
console.log(person.friends); //lisi,wangwu,zhaoliu,lihua
【注】:这种做法必须要有一个对象作为另一个对象的基础,上述代码中person对象就是作为另一个对象的基础
2.3寄生式继承
实现思路:创建一个仅用于封装继承过程的函数,在这个函数的内部增强对象,最后将增强后的对象返回
function object(o){
function F(){}
F.prototype = o;
return new F();
}
function createObj(original){
var clone = new object(original);
clone.sayHi = function(){
console.log('hi');
}
return clone;
}
var person = {
name:"zhangsan",
friends:["lisi","wangwu"]
}
var anotherPerson = createObj(person)
anotherPerson.sayHi();
2.4寄生组合式继承
function SuperType(name) {
this.name = name;
this.colors = ['red', 'green'];
}
SuperType.prototype.sayName = function () {
console.log(this.name);
};
function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
}
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function () {
console.log(this.age);
};
var instance = new SubType('zhangsan', 22);
instance.sayName();
instance.sayAge();