注意:
1,constructor总是指向类的构造函数
2,__proto__指向父类的原型对象
1,原型链继承
function Father(name){
this.name=name;
this.color=['red','blue'];
}
Father.prototype.getName=function(){
console.log(this.name)
}
function Child(){}
Child.prototype = new Father();
Child.prototype.constructor = Child;
var son1 = new Child('ming');
var son2 = new Child('wei');
son1.color.push('white');
son2.color; //['red','blue','white']
缺点:对于复杂数据类型color,多个实例对引用的操作会被篡改
2,借用构造函数继承
function Father(name){
this.name=name;
}
Father.prototype.getName=function(){
console.log(this.name)
}
function Son(name){
Father.apply(this,arguments);
}
var son = new Son('ming');
console.log(son.getName()) // son.getName is not a function
缺点:父类原型链上的属性和方法无法获取
3,组合继承(伪经典继承)
function Father(name) {
this.name = name;
this.color=['red','blue'];
}
Father.prototype.getName = function() {
console.log(this.name)
}
function Child(name) {
Father.apply(this, arguments);
}
Child.prototype = new Father();
Child.prototype.constructor = Child;
var son = new Child('ming');
console.log(son.color);
son.color.push('white')
var son2 = new Child('wei');
console.log(son2.color) //['red','blue']
基本ok,除了new Father()那个地方会多写一遍属性和方法,差不多还行
4,原型式继承(道爷-2006)
var Person={
name:'ming',
color:['red','blue']
}
function object(obj){
function F(){};
F.prototype=obj;
return new F();
}
var son1 = object(Person);
var son2 = object(Person);
son1.name='wei';
son1.color = ['white'];
console.log(son2.color); // ['red','blue','white']
缺点很明显:
1,原型实例指向的引用相同,可能存在篡改
2,不能传递参数
另:object方法已经由Object.create()实现
5,寄生式继承,(道爷有点皮)
创建一个函数,在内部构造新的属性和方法,以增强对象(原型式继承的加强版)
var Person = {
name: 'ming',
color: ['red', 'blue']
}
function object(obj) {
function F() {};
F.prototype = obj;
return new F();
}
function createSon(obj){
var son = object(obj);
console.log(son)
son.say=function(){
console.log('Hello,'+this.name)
}
return son;
}
var son1 = createSon(Person);
console.log(son1.name)
缺点很明显:
1,原型实例指向的引用相同,可能存在篡改
2,不能传递参数
6,寄生组合式继承(借用构造函数继承+寄生式继承)
function object(obj) {
function F() {};
F.prototype = obj;
return new F();
}
function inheritPerson(Person,Son){
var pro = object(Person.prototype);
Son.prototype.constructor=Son;
Son.prototype = pro;
}
function Person(name){
this.name=name;
this.color=['red','blue'];
}
Person.prototype.say=function(){
console.log('Hello,'+this.name)
}
function Son(name,age){
Person.call(this,name);
this.age = age;
}
inheritPerson(Person,Son);
Son.prototype.getAge=function(){
console.log(this.age);
}
var child1 = new Son('ming',20);
var child2 = new Son('wei',30);
child1.say() // ming
child1.color.push('white');
console.log(child2.color) //['red','blue']
这个是es5的终极解决方案
7,混入方式继承多个对象
function Father1(name){this.name=name}
function Father2(age){this.age=age}
function Son(name,age){
Father1.call(this,name);
Father2.call(this,age);
}
Son.prototype = Object.create(Father1.prototype);
Object.assign(Father1.prototype,Father2.prototype);
Son.prototype.constructor=Son;
var son1 = new Son('ming',20);
console.log(son1)
这个实际上是寄生组合式继承的加强版
8.class继承
class Person{
constructor(name){
this.name=name
}
say(){
console.log(this.name)
}
}
class Son extends Person{
constructor(name){
super(name)
}
}
使用babel转义为es5之后:
"use strict";
function _inheritsLoose(subClass, superClass) {
subClass.prototype = Object.create(superClass.prototype);
subClass.prototype.constructor = subClass;
subClass.__proto__ = superClass;
}
var Person =
function () {
function Person(name) {
this.name = name;
}
var _proto = Person.prototype;
_proto.say = function say() {
console.log(this.name);
};
return Person;
}();
var Son =
function (_Person) {
_inheritsLoose(Son, _Person);
function Son(name) {
return _Person.call(this, name) || this;
}
return Son;
}(Person);
总结:
1,类方法调用时不会变量提升:
var p = new P(); // Cannot access 'P' before initialization
class P{}
2,es6的继承,实际上是先创建父类的实例对象this,然后再用子类的构造函数修改this,因此在子类的contructor中要调用父类的super(),否则要报错。
参考资料:
1,https://juejin.im/post/5bcb2e295188255c55472db0#heading-0
2,https://www.liaoxuefeng.com/wiki/1022910821149312/1023021997355072