继承的实现基于原型链
1、原型链继承
将父类的实例作为子类的原型son.prototype = new father()
//父类型
function Parent (){
this.name = "farther"
this.color = ["red"]
}
Parent.prototype.sayname=function (){
return this.name}
function Son (){};
//继承
Son.prototype = new Parent()
var son =new Son()
console.log(son.name)
console.log(son.sayname()) //farther
var son2 =new Son();
son.color.push("blue")
console.log(son.color) //["red","blue"]
console.log(son2.color) //["red","blue"] 也变了
- 缺点
1、包含引用类型值的原型,会被所有实例共享
2、没办法在不影响其他实例的情况下,给父类型构造函数传递参数,
3、不能使用对象字面量创建原型方法,这样会重写原型。a.prototype={}
2、借用构造函数
在子类型的构造函数的内部调用超类型构造函数。
function Parent (){
this.name = "farther"
this.color = ["red"]
}
Parent.prototype.sayname=function (){
return this.name}
function Son(){
Parent.call(this)}
var son = new Son();
console.log(son.sayname()) //undefined访问不到
console.log(son.color)//["red"]
son.color.push("blue")
var son2 = new Son();
console.log(son.color)//["red","blue"]
console.log(son2.color)//["red"] 没有变
- 优点:可以传递参数通过call/apply
- 缺点:
1、方法都在构造函数中定义,函数无法复用。
2、原型中定义的属性方法对子类型是不可见的。sayname()是无法访问的。
3、组合继承
将原型链跟构造函数的技术组合到一块,发挥二者之长。
- 使用原型链实现对原型属性和方法的继承,
- 使用构造函数来实现对实例属性的继承。
//父类型
function Parent (){
this.name = "farther"
this.color = ["red"]
}
Parent.prototype.sayname=function (){
return this.name}
//子类型
function Son(){
Parent.call(this)} //继承属性
//继承方法
Son.prototype = new Parent()
//实例
var son = new Son();
son.color.push("blue")
console.log(son.color) //["red","blue"]
console.log(son.sayname()) //farther
var son2 = new Son();
console.log(son2.color)//["red"]
console.log(son2.sayname()) //farther
避免了原型链和借用构造函数的缺陷,融合了他们的优点。成为js中最常用的继承模式。
- 缺点:会调用两次超类型构造函数,一次是创建子类型构造函数时,一次是子类型构造函数内部。
- 生成了两份实例(子类实例将子类原型上的那份屏蔽了)
4、原型式继承
5、寄生式继承
6、寄生组合继承
通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点
function a(a,b){
//创建对象
var c =function (){};
c.prototype = a.prototype;
//将实例作为子类的原型
b.prototype = new c ()
}
//父类型
function Parent (){
this.name = "farther"
this.color = ["red"]
}
Parent.prototype.sayname=function (){
return this.name}
function Son(){
Parent.call(this)} //继承属性
a( Parent,Son);
var son = new Son();
son.color.push("blue")
console.log(son.color) //["red","blue"]
console.log(son.sayname()) //farther
通过一个立即执行函数作用域,在此作用域中创建一个临时类,临时类的原型 = 父类原型(解决构造函数继承中不能继承父类原型方法属性问题),
再将临时类的实例等于子类原型,因为是立即执行函数作用域,执行完就销毁了临时类的实例,也就避免了在组合继承里面保存了两份实例的问题。
7、使用ES6中的extends实现继承
//class 相当于es5中构造函数
//class中定义方法时,前后不能加function,全部定义在class的protopyte属性中
//class中定义的所有方法是不可枚举的
//class中只能定义方法,不能定义对象,变量等
//class和方法内默认都是严格模式
//es5中constructor为隐式属性
class Parent {
constructor(name){
this.name = "farther"
this.color = ["red"]
};
sayname(){
return this.name}
};
//继承父类
class Son extends Parent {
constructor() {
super();
}
}
var son = new Son();
son.color.push("blue")
console.log(son.color) //["red","blue"]
console.log(son.sayname()) //farther