# 原型
每个对象都有__proto__
属性,这个就是隐式原型,指向构造函数的原型 prototype,这个 prototype 就是显式原型。当查找属性时,先从构造函数中找,如果没有,则通过__proto__
,去构造函数的原型对象上找,也没有的话,会找到 Object.prototype,因为构造函数的原型对象也有__proto__
属性,指向 Object.prototype,如果还没有的话,则返回 undefined。由此形成了一条原型链。
只有(构造)函数才有 prototype。
# 原型链
# 继承
# 原型链继承
让子类的原型指向父类实例,继承父类所有的属性和方法
function Parent() {}
function Child() {}
Child.prototype = new Parent();
1
2
3
4
2
3
4
优点:
- 实现简单,通俗易懂
- 继承父类的所有的属性方法,包括构造函数和原型上的
缺点:
- 父类的引用类型属性会被共享
- 不能实现多继承,只能继承一个父类
- 创建子类实例时不能给父类传参
- 给子类原型添加方法必须放在更改子类原型指向语句的后面,否则新添加的方法不生效
- 子类实例和父类实例的构造函数都是父类构造函数,需要修复子类构造函数指向
# 构造函数继承
function Parent() {}
function Child() {
Parent.call(this, ...arguments);
}
1
2
3
4
5
2
3
4
5
优点:
- 解决了原型链继承共享父类引用类型属性的问题
- 可以多继承
- 创建子类实例时可以给父类传参
缺点:
- 只能继承父类构造函数的属性方法,不能继承父类原型,部分继承
# 组合继承
function Parent() {}
function Child() {
Parent.call(this, ...arguments);
}
Child.prototype = new Parent();
Child.prototype.constructor = Child; //修复子类原型的构造函数指向
1
2
3
4
5
6
7
2
3
4
5
6
7
# 组合继承优化 1
function Parent() {}
function Child() {
Parent.call(this, ...arguments);
}
Child.prototype = Parent.prototype;
Child.prototype.constructor = Child; //修复子类原型的构造函数指向
1
2
3
4
5
6
7
2
3
4
5
6
7
# 组合继承优化 2 (最佳实践)
function Parent() {}
function Child() {
Parent.call(this, ...arguments);
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child; //修复子类原型的构造函数指向
1
2
3
4
5
6
7
2
3
4
5
6
7
# ES6 extends 继承
class Parent {}
class Child extends Parent {}
1
2
3
2
3
# ES5 和 ES6 的继承有区别
ES5 继承的实现是先创建子类实例 this,给 this 上添加属性和方法 ES6 继承是先给父类 this 添加属性和方法,通过调用 super(),让子类继承父类的 this