目录
原型链的继承
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
};
function SubType(){
this.subproperty = false;
}
//inherit from SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function (){
return this.subproperty;
};
实现方法:
某一(理解为子类)原型对象等于另一(理解为父类)类型的实例
本质:
就是重写了子类的原型对象(所以需要注意的就是,通过使用原型链继承,就不能再使用对象字面量去创建原型方法,因为这样会再次重写原型链),子类原型对象包含一个指向父类原型对象的指针。
这样继承之后:
父类中的实例属性会在子类的原型对象中,父类中的原型中的东西依然在父类原型对象中。子类原型对象里面不会有constructor属性,除非自己补上
原型链带来的问题:
1、父类中的实例属性会变成子类原型对象中的属性
2、在创建子类型的实例时,不能向父类型的构造函数中传递参数
借用构造函数继承
function SuperType(){
this.colors = ["red", "blue", "green"];
}
function SubType(){
//inherit from SuperType
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"
实现方法:
子类型构造函数内部直接调用父类函数(当然,要通过apply或call改变this指向)
本质:父类中实例属性的继承,就是子类实例属性中有父类实例属性的副本
继承之后:子类实例属性中有父类实例属性的副本
优点与问题:优点:子类构造函数中调用父类构造函数的时候可以向其传递参数
缺点:方法写在构造函数中,函数的复用无从谈起,而且父类原型对象中定义的方法,子类并不可见,所以就有了原型链与借用构造函数相结合的组合继承
组合继承
就是利用原型链实现对原型对象中属性和方法的继承,利用借用构造函数实现对实例属性的继承。
懂了前面两个,这个来个例子看看就会明白
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();//原型链继承
SubType.prototype.sayAge = function(){
alert(this.age);
};
var instance1 = new SubType("Nicholas", 29);
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
但是呢,组合继承也有它的缺点。大家有没有发现,在组合继承中,有两次调用了父类的构造函数,第一次在原型链继承的地方,就是子类的原型对象中会存储父类构造函数里属性和方法;第二次调用是在子类的构造函数内,这样 父类构造函数里属性和方法又会变成子类实例的属性和方法,所以就有屏蔽子类原型中的。
如何解决这个问题,就是待会会说到的寄生组合式继承。
原型式继承
function object(o){//原型式继承
function F(){}
F.prototype = o; //以传进来的对象为基础,返回的实例中,改实例的原型对象指向o
return new F();
}
原型式继承首先在object()
函数内部创建一个临时性的构造函数 ,然后将传入的对象作为这个构造函数的原型,最后返回这个临时类型的一个新实例。
所有的实例都是共享这一个原型对象(就是在一个实例中更改了原型中的值,其他实例中的值也会有更改)
看例题:
function object(o){//原型式继承
function F(){}
F.prototype = o;
return new F();
}
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = object(person);
anotherPerson.friends.push("Rob");
var yetAnotherPerson = object(person);
yetAnotherPerson.friends.push("Barbie");
alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"
//稍微优化
(function object(){//原型式继承
function F(){}
return function(o){
F.prototype = o;
return new F();
}
})()
寄生式继承
这种继承方式是把原型式+工厂模式结合起来,目的是为了封装创建的过程。
function create(o){
var f= object(o);
f.run = function () {
return this.arr;//同样,会共享引用
};
return f;
}
寄生组合式继承
根据组合继承改进,原有的借用构造函数继承不变,改变原型链继承的方式,不通过调用父类构造函数,而是通过以下方法:
第一步:创建父类原型的一个副本(利用原型式继承)
第二步:增强上面创建的对象
第三步:将上面创建的对象赋值给子类对象的原型
实现代码如下:
function inheritPrototype(subType,superType) {
var prototype = object(superType.prototype);//第一步
prototype.constructor = subType;//第二步
subType.prototype = prototype;//第三步
}
function create(o){
var f= object(o);
f.run = function () {
return this.arr;//同样,会共享引用
};
return f;
}
function object(o){//原型式继承
function F(){}
F.prototype = o;
return new F();
}
完整例子(class类编译后的代码)
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
// 兼容
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
}
return function (d, b) {
// 继承静态属性
extendStatics(d, b);
// 原型式继承
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var Animal = /** @class */ (function () {
function Animal(theName) {
this.name = theName;
}
Animal.hi = function(){console.log('hi')}
Animal.prototype.move = function (distanceInMeters) {
if (distanceInMeters === void 0) { distanceInMeters = 0; }
console.log(this.name + " moved " + distanceInMeters + "m.");
};
return Animal;
}());
var Snake = /** @class */ (function (_super) {
__extends(Snake, _super);// 静态方法和原型式继承
function Snake(name, age) {
// 为什么一定要写super(),编译的时候不能直接加进去?我觉得是为了继承父类中的属性,还可以传值进行初始化,没写super编译后就是var _this,下面也拿不到this对象
var _this = _super.call(this, name) || this;//借用父类构造函数继承父类的实例属性和方法到子类的实例上
_this.age = age;
return _this;
}
Snake.prototype.move = function (distanceInMeters) {
if (distanceInMeters === void 0) { distanceInMeters = 5; }
console.log("Slithering...");
_super.prototype.move.call(this, distanceInMeters);
};
return Snake;
}(Animal));
var sam = new Snake("Sammy the Python");
sam.move();
Snake.hi()