我们用new一个构造函数的方法生成一个实例,比如:
function a() { this.b=2; }
var b = new a()
复制代码
new 这个关键字做了什么?
- var b = {}
- b.proto = a.prototype;
- var res = a.call(b)
- return typeof res === 'object' ? res : b;
当谈到继承时,JavaScript 只有一种结构:对象。每个实例对象(object )都有一个私有属性(称之为__proto__)指向它的原型对象(prototype)。给几个例子,B继承自A。
构造函数实现继承
function parent(b) {
console.log(b);
this.name = b;
}
console.log(parent); // 会打印出上述函数
parent.prototype.say = function () {
console.log('abc');
};
function child (b) {
parent.call(this, b);
console.log(parent.call(this, b)); // call 会改造this
this.xixi = 2;
}
复制代码
有个缺陷,这个方法不能继承父类的say方法
原型链继承
原型链是 javascript 的典型继承方式, 这种继承方式的最大特点就是共享,所有事例共享原型对象中的所有属性和方法。
function parent(b) {
this.name = b;
}
parent.prototype.xixi = '123';
function child() {
this.a=1;
}
child.prototype = new parent(b);
child.prototype.constructor = parent // 保持构造函数和原型对象的完整性
console.log(new child());
复制代码
缺点,new出来的实例通过参数传值赋值的话,一经初始化就永久有个初始值了。所以是无法向父类传参,无法实现多继承的。
组合式继承
简单点来说就是构造函数继承 + 原型链继承,实现了继承,这样父类和子类可以分别拥有自己的实例化属性。
function parent (b) {
this.name = b;
}
function child (b) {
parent.call(this, b);
this.xixi = 1;
}
child.prototype = new parent();
child.prototype.constructor = child;
复制代码
既是子类的实例,也是父类的实例, 但有一个缺点就是调用了两次父类构造函数,造成内存浪费。而且可能发生变量覆盖问题。
寄生组合式继承
改进了一步,使用了Object.create方法,不会造成内存浪费。
function parent (b) {
this.name = b;
}
function child (b) {
parent.call(this, b);
this.xixi = 1;
}
child.prototype = Object.create(parent);
child.prototype.constructor = child;
复制代码
es6 extends
也有寄生组合式继承的优点,通过super来传递父类拿到的参数
class parent {
constructor(prop) {
console.log(prop);
}
}
class child extends parent {
constructor(prop) {
super(prop);
console.log(prop)
}
}
new child('bb')
复制代码