原型链
思想:基于原型链实现继承,将子类的原型对象设为父类的实例对象,使得子类可以访问父类的属性和方法。
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function () {
return this.property;
};
function SubType() {
this.subproperty = false;
}
//实现继承
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function () {
return this.subproperty;
};
let instance = new SubType();
console.log(instance.getSuperValue()); //true
痛点
1、父类对象的实例属性变成了子类的原型对象
2、子类在实例化对象时不能给父类的构造函数传参
function SuperType() {
this.colors = ["red", "blue", "green"];
}
function SubType() {}
//实现继承
SubType.prototype = new SuperType();
let instance1 = new SubType();
let instance2 = new SubType();
instance1.colors.push("black");
console.log(instance1.colors);//[ 'red', 'blue', 'green', 'black' ]
console.log(instance2.colors);//[ 'red', 'blue', 'green', 'black' ]
构造函数
思想:子类构造函数盗用父类的构造函数,利用call()改变this的指向。
SubType在生成实例对象时运行了SuperType构造函数中的所有初始代码,使得每个SubType对象都有自己的colors属性,同时SubType在生成实例对象时可以给SuperType的构造函数传递参数
function SuperType(_name) {
this.colors = ["red", "blue", "green"];
this.name = _name;
}
function SubType(_name) {
SuperType.call(this, _name);
}
let instance1 = new SubType("lbw");
let instance2 = new SubType("white");
instance1.colors.push("black");
console.log(instance1.colors, instance1.name); //[ 'red', 'blue', 'green', 'black' ] lbw
console.log(instance2.colors, instance2.name); //[ 'red', 'blue', 'green' ] white
痛点:
1、函数必须定义在构造函数中,函数无法复用。每生成一个实例对象就会开辟新的内存空间,资源浪费
2、子类无法调用父类原型上的属性和方法
组合继承
原型链和构造函数结合体。
function SuperType(_name) {
this.colors = ["red", "blue", "green"];
this.name = _name;
}
SuperType.prototype.getName = function () {
console.log(this.name);
};
function SubType(_name, age) {
//盗用构造函数继承属性
SuperType.call(this, _name);
this.age = age;
}
//原型链继承方法
SubType.prototype = new SuperType();
SubType.prototype.getAge = function () {
console.log(this.age);
};
let instance1 = new SubType("lbw", 18);
instance1.colors.push("black");
console.log(instance1.colors); //[ 'red', 'blue', 'green', 'black' ]
instance1.getName(); //lbw
instance1.getAge(); //18
let instance2 = new SubType("white", 28);
console.log(instance2.colors); //[ 'red', 'blue', 'green' ]
instance2.getName(); //white
instance2.getAge(); //28
痛点:
1、父类构造函数最终会执行两次,存在效率问题
2、子类原型对象上的属性和方法冗余了
function SuperType(_name) {
this.colors = ["red", "blue", "green"];
this.name = _name;
}
SuperType.prototype.getName = function () {
console.log(this.name);
};
function SubType(_name, age) {
SuperType.call(this, _name);//第二次执行
this.age = age;
}
SubType.prototype = new SuperType();//第一次执行
//SubType.prototype存在多余的属性colors和name
SubType.prototype.getAge = function () {
console.log(this.age);
};
const instance = new SubType("lbw", 18);
console.log(SubType.prototype.colors); //[ 'red', 'blue', 'green' ]
寄生组合继承
只调用一次父类函数的构造函数,同时避免了子类原型对象上多余的属性,目前实现继承的最优方式
function SuperType(_name) {
this.colors = ["red", "blue", "green"];
this.name = _name;
}
SuperType.prototype.getName = function () {
console.log(this.name);
};
function SubType(_name, age) {
SuperType.call(this, _name);
this.age = age;
}
SubType.prototype = Object.create(SuperType.prototype);
//Object.create()返回一个空对象,函数参数将作为空对象的原型对象
SubType.prototype.constructor = SubType;
SubType.prototype.getAge = function () {
console.log(this.age);
};
let instance1 = new SubType("lbw", 18);
instance1.colors.push("black");
console.log(instance1.colors); //[ 'red', 'blue', 'green', 'black' ]
instance1.getName(); //lbw
instance1.getAge(); //18
let instance2 = new SubType("white", 28);
console.log(instance2.colors); //[ 'red', 'blue', 'green' ]
instance2.getName(); //white
instance2.getAge(); //28
console.log(SubType.prototype.colors); //undefined