继承

191 阅读4分钟

一、原型链继承(类式继承)

function Person(){
    this.type = 'father';
    this.arr = [1,2,3]
    this.sum = function(){
    	return 'per1'
    }
}
Person.prototype.age = 99;
Person.prototype.sayName = function(){
	return 'superType'
}

function Son(name){
	this.name = name;
}
Son.prototype = new Person(); //类式继承

var son1 = new Son('son1Name')

console.log(son1.name); // sonName
console.log(son1.age); // 99
console.log(son1.type); // 'father'
console.log(son1.arr); // [1,2,3]
console.log(son2 instanceof Son); // true
console.log(son1 instanceof Person); // true
console.log(son1.sum()); // per1
console.log(son1.sayName()); // superType
son1.type = 'newFather'
son1.age = 101
son1.arr.push('1111')

var son2 = new Son('son2Name')
console.log(son2.name); // son2Name
console.log(son2.age); // 99
console.log(son2.type); // 'father'
console.log(son2.arr); // [1,2,3,'1111']
console.log(son2 instanceof Son); // true
console.log(son2 instanceof Person); // true
console.log(son2.sum()); // per1
console.log(son2.sayName()); // superType

让新势实例的原型等于父类的实例

** 特点:**

  • 继承了实例的构造函数属性
  • 继承了父类构造函数属性
  • 继承了父类原型属性

** 缺点:**

  • 新实例无法向父类构造函数传参
  • 引用类型会被子类的所有实例化对象共享(一个实例修改,另一个实例也会跟着被修改)

二、借用构造函数继承

function Person(){
    this.type = 'father';
    this.arr = [1,2,3]
    this.sum = function(){
    	return 'per1'
    }
}
Person.prototype.age = 99;
Person.prototype.sayName = function(){
	return 'superType'
}

function Son(name){
    Person.call(this)// 构造函数
	this.name = name;
}

var son1 = new Son('son1Name')

console.log(son1.name); // sonName
console.log(son1.age); // underfind
console.log(son1.type); // 'father'
console.log(son1.arr); // [1,2,3]
console.log(son2 instanceof Son); // true
console.log(son1 instanceof Person); // false
console.log(son1.sum()); // per1
console.log(son1.sayName()); // 报错
son1.type = 'newFather'
son1.age = 101
son1.arr.push('1111')

var son2 = new Son('son2Name')
console.log(son2.name); // son2Name
console.log(son2.age); // underfind
console.log(son2.type); // 'father'
console.log(son2.arr); // [1,2,3]
console.log(son2 instanceof Son); // true
console.log(son2 instanceof Person); // false
console.log(son2.sum()); // per1
console.log(son2.sayName()); // 报错

用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))

** 特点:**

  • 只继承了父类构造函数的属性、方法,没有继承父类原型的属性、方法
  • 在子类中可以向附实例传参
  • 可以继承多个构造函数属性
  • 更改本实例的引用属性其余实例不会更改

** 缺点:**

  • 只能继承构造函数的属性
  • 无法实现函数复用(每次都需要重新调用)
  • 每个实例都有父类构造的副本,臃肿

三、组合继承

function Person(){
    this.type = 'father';
    this.arr = [1,2,3]
    this.sum = function(){
    	return 'per1'
    }
}
Person.prototype.age = 99;
Person.prototype.sayName = function(){
	return 'superType'
}

function Son(name){
    Person.call(this) //组合式
	this.name = name;
}
Son.prototype = new Person() //组合式

var son1 = new Son('son1Name')

console.log(son1.name); // sonName
console.log(son1.age); // 99
console.log(son1.type); // 'father'
console.log(son1.arr); // [1,2,3]
console.log(son2 instanceof Son); // true
console.log(son1 instanceof Person); // true
console.log(son1.sum()); // per1
console.log(son1.sayName());  // superType
son1.type = 'newFather'
son1.age = 101
son1.arr.push('1111')

var son2 = new Son('son2Name')
console.log(son2.name); // son2Name
console.log(son2.age); // 99
console.log(son2.type); // 'father'
console.log(son2.arr); // [1,2,3]
console.log(son2 instanceof Son); // true
console.log(son2 instanceof Person); // true
console.log(son2.sum()); // per1
console.log(son2.sayName());  // superType

采用原型链和构造函数的组合

** 特点:**

  • 可以继承父类原型上属性和方法,可以传参,可复用。
  • 每个实例所引入的构造函数属性是私有的。

** 缺点:**

  • 调用了两次父类构造函数(耗内存)

四、原型式继承

function Person(){
    this.type = 'father';
    this.arr = [1,2,3]
    this.sum = function(){
    	return 'per1'
    }
}
Person.prototype.age = 99;
Person.prototype.sayName = function(){
	return 'superType'
}

function Son(name){
	this.name = name;
}
var per1 = new Person() //原型式
Son.prototype = Object.create(per1) //原型式
Son.prototype.constructor = Son  //原型式

var son1 = new Son('son1Name')

console.log(son1.name); // sonName
console.log(son1.age); // 99
console.log(son1.type); // 'father'
console.log(son1.arr); // [1,2,3]
console.log(son2 instanceof Son); // true
console.log(son1 instanceof Person); // true
console.log(son1.sum()); // per1
console.log(son1.sayName());  // superType
son1.type = 'newFather'
son1.age = 101
son1.arr.push('1111') 

var son2 = new Son('son2Name')
console.log(son2.name); // son2Name
console.log(son2.age); // 99
console.log(son2.type); // 'father'
console.log(son2.arr); // [1,2,3,'1111']
console.log(son2 instanceof Son); // true
console.log(son2 instanceof Person); // true
console.log(son2.sum()); // per1
console.log(son2.sayName());  // superType

原型式继承的是对类式继承的一个封装,它的内部构造了一个空的函数,将这个函数的原型对象赋予父对象的值,然后返回一个空函数的实例对象。

function F(obj){};
F.prototype = obj //obj是父对象
return new F();

它的缺点与类式继承是一样的,父类的引用类型会被共用。只是它构造了一个空函数,开销会小一点。

五、寄生式继承

function Person(){
    this.type = 'father';
    this.arr = [1,2,3]
    this.sum = function(){
    	return 'per1'
    }
}
Person.prototype.age = 99;
Person.prototype.sayName = function(){
	return 'superType'
}

function Son(name){
	this.name = name;
}
var per1 = new Person() //寄生式
per1.inherit = 'inherit'; //寄生式
per1.inherit2 = 'inherit2' //寄生式
Son.prototype = Object.create(per1) //寄生式
Son.prototype.constructor = Son  //寄生式

var son1 = new Son('son1Name')

console.log(son1.inherit); // inherit
console.log(son1.inherit2); // inherit2
console.log(son1.name); // sonName
console.log(son1.age); // 99
console.log(son1.type); // 'father'
console.log(son1.arr); // [1,2,3]
console.log(son2 instanceof Son); // true
console.log(son1 instanceof Person); // true
console.log(son1.sum()); // per1
console.log(son1.sayName());  // superType
son1.type = 'newFather'
son1.age = 101
son1.arr.push('1111') 

var son2 = new Son('son2Name')
console.log(son2.inherit); // inherit
console.log(son2.inherit2); // inherit2
console.log(son2.name); // son2Name
console.log(son2.age); // 99
console.log(son2.type); // 'father'
console.log(son2.arr); // [1,2,3,'1111']
console.log(son2 instanceof Son); // true
console.log(son2 instanceof Person); // true
console.log(son2.sum()); // per1
console.log(son2.sayName());  // superType

寄生式继承顾名思义,它可以对继承的对象进行扩展,为其增加新的属性和方法

六、寄生组合式继承

function Person(){
    this.type = 'father';
    this.arr = [1,2,3]
    this.sum = function(){
    	return 'per1'
    }
}
Person.prototype.age = 99;
Person.prototype.sayName = function(){
	return 'superType'
}

function Son(name){
	Person.call(this)寄生组合式
	this.name = name;
}

Son.prototype = Object.create(Person.prototype)寄生组合式
Son.prototype.constructor = Son 寄生组合式

var son1 = new Son('son1Name')

console.log(son1.name); // sonName
console.log(son1.age); // 99
console.log(son1.type); // 'father'
console.log(son1.arr); // [1,2,3]
console.log(son2 instanceof Son); // true
console.log(son1 instanceof Person); // true
console.log(son1.sum()); // per1
console.log(son1.sayName());  // superType
son1.type = 'newFather'
son1.age = 101
son1.arr.push('1111') 

var son2 = new Son('son2Name')

console.log(son2.name); // son2Name
console.log(son2.age); // 99
console.log(son2.type); // 'father'
console.log(son2.arr); // [1,2,3]
console.log(son2 instanceof Son); // true
console.log(son2 instanceof Person); // true
console.log(son2.sum()); // per1
console.log(son2.sayName());  // superType

使用Object.create()方法还有一个小瑕疵,它需要抛弃默认的Son.prototype,重新创建了一个对象,不能修改已有的默认对象。因此ES6之后又添加了一个辅助函数Object.setPrototypeOf(),直接修改对象的[[prototype]]关联。

Son.prototype = Object.create(Person.prototype)
Son.prototype.constructor = Son 
// 可以替换为
Object.setPrototypeOf(Son.prototypePerson.prototype)

继承的原型链图谱

** es5的组合继承:**

** es6的class继承:**

图片参考:blog.csdn.net/qq_30282133…