1.原型链继承
原型链继承也是最常见的继承方式
//定义带属性的父类
function F(){
this.control = true
}
//定义方法绑定到父类的属性上
F.prototype.getControl = function(){
return this.control
}
//创建子类
function f(){
this.fcontrol = false
}
//继承
f.prototype = new F();
//给字类添加字类特有的方法(必须在继承后才能添加)
f.prototype.getMark = function(){
return this.fcontrol
}
缺点:构造函数原型上的属性在所有创建的实例上都是共享的,没有实现私有化,原型上属性的更改会导致所有实例的属性更改,而且也没有办法在不影响所有对象实例的情况下,给超类型的函数传递参数,因此实践中很少单独使用原型链继承
2.构造函数实现继承
在子类型构造函数的内部调用超类型构造函数,使用call()或apply()来实现继承
//创建父类
function F(){
this.name = ["a","b","c"];
}
//创建子类
function f(){
F.call(this) //可直接传递参数
}
//创建实例
var obj1 = new f()
obj1.name.push("d")
console.log(obj1.name) //a,b,c,d
var obj2 = new f()
console.log(obj2.name) //仍是a,b,c
//创建父类
function F(name){
this.name = name
}
function f(){
F.call(this,"sss"); //继承的同时传递参数
this.age = 19
}
var obj1 = new f()
console.log(obj1.name) //sss
console.log(obj1.age) //19
优缺点:构造函数继承相对于原型链而言可以向超类型构造函数传递子类型构造函数的参数
实现了属性的私有化但是子类无法访问父类的属性
3.组合继承
利用构造函数和原型链的方法组合继承
使用原型链实现对原型函数方法和属性的继承,通过构造函数实现对实例属性的继承
function F(name){
this.name = name;
this.colors = ["red","blue","black"];
}
F.prototype.howOld = function(){
console.log(this.ages) //添加howold方法
}
function f(name,age){
F.call(this,name); //调用f构造函数传入name属性
this.age = age;
}
f.prototype = new F();
f.prototype.constroctor = f; //当前指向构造函数为f
f.prototype.sayName = function(){
console.log(this.name);
}
var ins = new f("sss",19);
ins.colors.push("pink");
console.log(ins.colors) //red,blue,black,pink
ins.sayName() //sss
ins.howOld() //19
var ins1 = new f("bgc",21);
console.log(ins1.colors) //red,blue,black
console.log(ins1.sayName()) //bgc
console.log(ins1.howOld()) //21
与上两种方法对比:组合继承避免了原型链和构造函数的缺陷,让f的两个实例分别拥有自己的属性包括超类型构造函数F的属性,又可以使用相同的方法
4.寄生式继承
寄生式继承也是一种有用的继承方式,即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式增强对象
function par(person){
var a = object(person);
a.sayName = function(){
console.log("sss");
};
return a;
}
var b = {
name:"bgc";
colors:["red","black","pink"]
};
var c = par(b);
c.sayName() //sss
构造函数内的object()函数并非必须的,任何可以返回新函数的方法都适用寄生式继承