确定原型和实列的关系
- instance instanceof ClassName
- ClassName.prototype.isPrototypeOf(instance)
1. es6的extends
清晰方便
// es6继承
class Point {
x;
y;
constructor(x, y) {
this.x = x;
this.y = y;
}
print() {
console.log(`Point:(${this.x},${this.y})`);
}
}
class ColorPoint extends Point {
color;
constructor(x, y, color) {
// 必须调用父类构造函数
super(x, y);
this.color = color;
}
// 覆盖父类方法
print() {
console.log(`ColorPoint:(${this.x},${this.y}) ${this.color}`);
}
}
const p = new Point(1, 2);
p.print(); // Point:(1,2)
const cp = new ColorPoint(3, 4, "red");
cp.print(); // ColorPoint:(3,4) red
2. 原型链继承
通过让子类的prototype等于父类的实例来实现继承
两个缺点
1. 因为所有子类的__proto__指向是同一个父类的实例,这会导致对这个实例引用类型的修改,作用于所有的子类上
2. 创建子类实例的时候,不能向父类的构造函数传递参数
function Point(x, y) {
this.x = x;
this.y = y;
this.arr = [x, y];
}
Point.prototype.print = function () {
console.log(`Point:(${this.x},${this.y})`);
};
function ColorPoint(color) {
this.color = color;
}
// 将子类的prototype改成父类的实例
ColorPoint.prototype = new Point(1, 2);
ColorPoint.prototype.print = function () {
console.log(`ColorPoint:(${this.x},${this.y}) ${this.color} [${this.arr}]`);
};
const cp = new ColorPoint("red");
cp.print(); // ColorPoint:(1,2) red [1,2]
const cp2 = new ColorPoint("blue");
cp2.x = 233; // 这种操作只是在cp2增加了一个x属性,不会影响cp的x
cp2.arr[0] = 10086; // 这种操作修改了父类的那个实例的arr的值,会影响到cp
cp2.print(); // ColorPoint:(233,2) blue [10086,2]
cp.print(); // ColorPoint:(1,2) red [10086,2]
3.借用构造函数(伪造对象 经典继承)
在子类的构造函数中,使用apply(入参是是数组)或者call(入参是一个个)方法调用父类的构造函数
缺点
因为实际只是借用了父类的构造函数,所以定义在父类原型中的方法,子类没有继承。instanceof检查也会是false
function Point(x, y) {
this.x = x;
this.y = y;
this.arr = [x, y];
}
Point.prototype.print = function () {
console.log(`Point:(${this.x},${this.y})`);
};
function ColorPoint(x, y, color) {
Point.call(this, x, y);
this.color = color;
}
ColorPoint.prototype.printColor = function () {
console.log(`ColorPoint:(${this.x},${this.y}) ${this.color} [${this.arr}]`);
};
const cp = new ColorPoint(1, 2, "red");
// cp.print(); // 没有继承prit方法,报错
cp.printColor(); // ColorPoint:(1,2) red [1,2]
console.log(cp instanceof Point); // false
console.log(cp instanceof ColorPoint); // ture
4.组合继承(伪经典继承)
结合了原型链继承和借用构造函数的技术。通过借用构造函数实现对实例属性的继承,通过原型链实现对原型属性和方法的继承(new父类的实例时不需要参数)。
缺点
调用了两次父类的构造函数,一次是new父类实例的时候,一次在子类构造函数call
function Point(x, y) {
this.x = x;
this.y = y;
this.arr = [x, y];
}
Point.prototype.print = function () {
console.log(`Point:(${this.x},${this.y})`);
};
function ColorPoint(x, y, color) {
// 第二次调用父类构造函数
Point.call(this, x, y);
this.color = color;
}
// 第一次调用父类构造函数
ColorPoint.prototype = new Point(); // 不需要参数
ColorPoint.prototype.constructor = ColorPoint;
ColorPoint.prototype.printColor = function () {
console.log(`ColorPoint:(${this.x},${this.y}) ${this.color} [${this.arr}]`);
};
const cp = new ColorPoint(1, 2, "red");
cp.print(); // Point:(1,2)
cp.printColor(); // ColorPoint:(1,2) red [1,2]
console.log(cp instanceof Point); // true
console.log(cp instanceof ColorPoint); // ture
5.原型式继承
类似原型链继承,让子类的prototype等于父类的实例来实现继承。不过这里没有父类,只有一个对象,这种情况适用于让一个对象和另一个对象保持类似。
ES5的Object.create也能做到这样的效果:创建一个新对象,使用现有的对象来提供新创建的对象的__proto__
缺点同原型链继承
所有子类的__proto__指向是那个对象,这会导致对这个实例引用类型的修改,作用于所有的子类上
const point = {
x: 1,
y: 2,
arr: [1, 2],
print: function () {
console.log(`Point:(${this.x},${this.y}) ${this.arr}`);
},
};
function ColorPoint(obj) {
function f() {}
f.prototype = obj;
return new f();
}
const cp = ColorPoint(point);
cp.print(); // Point:(1,2) 1,2
cp.arr.push(10086);
const cp2 = Object.create(point);
cp2.print(); // Point:(1,2) 1,2,10086
console.log(cp instanceof ColorPoint); // false
6.寄生组合式继承
使用空函数代替父类构造函数去创建实例,解决了组合继承调用两次父类构造函数的问题
function inherit(father, child) {
function f() {}
f.prototype = father.prototype;
const obj = new f();
// 类似ColorPoint.prototype = new Point();
// 但是因为f是空函数,所以不需要执行父类的构造函数
child.prototype = obj;
obj.constructor = child;
}
function Point(x, y) {
this.x = x;
this.y = y;
this.arr = [x, y];
}
Point.prototype.print = function () {
console.log(`Point:(${this.x},${this.y})`);
};
function ColorPoint(x, y, color) {
Point.call(this, x, y);
this.color = color;
}
// 继承
inherit(Point, ColorPoint);
// 要在继承完毕后才能加属性,因为继承改了prototype
ColorPoint.prototype.printColor = function () {
console.log(`ColorPoint:(${this.x},${this.y}) ${this.color} [${this.arr}]`);
};
const cp = new ColorPoint(1, 2, "red");
cp.print(); // Point:(1,2)
cp.printColor(); // ColorPoint:(1,2) red [1,2]
console.log(cp instanceof Point); // true
console.log(cp instanceof ColorPoint); // ture
?代码库
|