1.基于原型的继承
function Person() {
this.name = 'zhangsan';
}
function Woman(age) {
this.age = age;
}
Woman.prototype = new Person();
var woman1 = new Woman(18);
console.log(woman1); //Woman {age: 18}age: 18__proto__: Personname: "zhangsan"__proto__: Object
通过原型链,将子类构造函数的原型对象(prototype)重写,赋值为一个父类的实例,因为每个实例都会有一个proto指针指向自身的原型对象,而另一个父类的原型对象在次被重写,定义为一个实例,层层嵌套,就形成了原型的继承
缺点:不能传递参数,实例会共享所有引用类型的原型属性
2.借用构造函数的继承
function Person (name) {
this.name = name;
}
function Woman (name,age) {
Person.call(this,name);
this.age = age;
}
var woman1 = new Woman('zhangsan',18);
console.log(woman1); //Woman {name: "zhangsan", age: "zhangsan"}
将父类的构造函数在子类的上下文环境下调用,因为函数只是在特定环境下执行的对象,上面的代码中使用call(apply也是可以的),在要通过Woman方法新创建实例的时候,在实例环境下调用了Person的构造函数,这个时候因为执行上下文环境是在Woman中,this的指向是在Woman的实例,所以Woman的每个实例就会有name属性
缺点:函数都在构造函数中定义,函数无法复用
3.组合继承
function Person (name) {
this.name = name;
}
Person.prototype.test = function () {
console.log(1);
}
function Woman (name,age) {
Person.call(this,name);
this.age = age;
}
Woman.prototype = new Person();
Woman.prototype.test1 = function () {
console.log(2);
}
var woman1 = new Woman('zhangsan',18);
console.log(woman1); //Woman {name: "zhangsan", age: 18}
woman1.test(); //1
将原型链和借用构造函数继承组合到一起,通过原型链使用对方法和属性的继承,又能传递参数,实现对实例属性的继承
缺点:会调用两个超类型的构造函数,一次是在创建子类原型的时候,一次是在子类型构造函数的内部,第一次调用父类的构造函数,Woman的原型会得到一个属性(name),他们是父类的实例属性,只不过现在是位于Woman的原型对象上,当调用Woman的构造函数时,又会调用一次父类的构造函数,这一次是在实例对象上创建了实例属性name,这个name会屏蔽原型中的name
4.原型式继承
function obj (o) {
function F() {};
F.prototype = o;
return new F();
}
var obj1 = {
name: 'zhangsan',
age: 18
}
var obj2 = obj(obj1);
console.log(obj2.name); //zhangsan
原型式继承必须有一个对象作为另一个对象的基础,相当于对obj1进行了一次浅复制,这里可以看着对F的构造函数进行了重写,将o(一个实例化对象)赋值给了F的原型对象,然后返回的是一个F的实例,着和原型链的继承方式和类似
5.寄生式继承
function obj(o) {
function F() {};
F.prototype = o;
return new F();
}
function createAnother(o) {
var clone = obj(o);
clone.test = function() {
console.log(1);
};
return clone;
}
var obj1 = {
name: 'zhangsan',
age: 18
}
var obj2 = createAnother(obj1);
obj2.test(); //1
console.log(obj2);
6.寄生组合式继承
function obj(o) {
function F() {};
F.prototype = o;
return new F();
}
function AnotherObj(Woman, Person) {
var prototype = obj(Person.prototype);
prototype.constructor = Woman;
Woman.prototype = prototype;
}
function Person(name) {
this.name = name;
this.sex = 'nan';
}
Person.prototype.test = function() {
console.log(1);
}
function Woman(name, age) {
Person.call(this, name);
this.age = age;
}
AnotherObj(Woman, Person);
Woman.prototype.test1 = function() {
console.log(2);
}
var woman1 = new Woman('zhangsan', 18);
console.log(woman1); //Woman {name: "zhangsan", age: 18}
woman1.test(); //1
优点:只调用了一次父类的构造函数(Person),并且避免了在子类的原型对象上面创建不必要的、多余的属性,而且子类的原型链可以保持不变,是理想型的继承实现的方式