注意:
- constructor总是指向类的构造函数
- __proto__指向父类的原型对象
- instanceof可以判断构造函数的继承关系
一、原型链继承
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,多个实例对引用的操作会被篡改
二、借用构造函数继承
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
缺点:父类原型链上的属性和方法无法获取
三、组合继承(伪经典继承)
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()那个地方会多写一遍属性和方法,差不多还行
四、原型式继承(道爷-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()实现
五、寄生式继承,(道爷有点皮)
创建一个函数,在内部构造新的属性和方法,以增强对象(原型式继承的加强版)
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,不能传递参数
六、寄生组合式继承(借用构造函数继承+寄生式继承)
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的终极解决方案
七、混入方式继承多个对象
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)
这个实际上是寄生组合式继承的加强版
八、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);
总结
- 类方法调用时不会变量提升:
var p = new P(); // Cannot access 'P' before initialization class P{}
- es6的继承,实际上是先创建父类的实例对象this,然后再用子类的构造函数修改this,因此在子类的contructor中要调用父类的super(),否则要报错。