原型链继承
传统的继承方式,主要存在一种继承关系:Child.prototype.__proto__ === Parent.prototype
推导:
// 已知
const child = new Child();
child.__proto__ === Child.prototype;
Child.prototype = new Parent();
// 因为
let p = new Parent();
p.__proto__ === Parent.prototype;
// 所以
// 出现这个等式之后,就说明存在了一种继承关系!
Child.prototype.__proto__ === Parent.prototype
复制代码
原型链继承:
function Parent() {
this.name = 'parentName';
this.actions = [1,2];
}
Parent.prototype.getName = function() {
console.log(this.name);
}
function Child(){};
// 原型链继承
Child.prototype = new Parent(); // 确定继承关系
Child.prototype.constructor = Child; // 做一个constructor的类型矫正。不写,则指向 Parent
// 如果 Child.prototype = Parent.prototype 则Child只能继承原型上的属性方法,不能继承实例上的属性方法
let c1 = new Child();
c1.actions.push(3); // 一旦修改,所有实例都会有影响
console.log(c1.actions); // [1,2,3]
let c2 = new Child();
console.log(c2.actions); // [1,2,3]
复制代码
问题:
- 如果有属性是引用类型的,一旦某个实例修改了这个属性,所有实例都会受到影响
- 创建 Child 实例的时候,不能传参
可用 构造函数继承 解决这两个问题。
构造函数继承
主要代码:Parent.call(this,name,actions)
function Parent(name, actions) {
this.actions = actions;
this.name = name;
}
function Child(id, name, actions) {
this.id = id;
Parent.call(this, name, actions);
// 如果想直接传多个参数, 可以
Parent.apply(this, Array.from(arguments).slice(1));
}
const child1 = new Child(1, "c1", ["eat"]);
const child2 = new Child(2, "c2", ["sing", "jump", "rap"]);
console.log(child1.eat === child2.eat); // false
复制代码
问题:
- 属性或者方法想被继承的话,只能在构造函数中定义。而如果方法在构造函数中定义了,那么每次创建实例都会创建一遍方法,多占一块内存
简单来说:重复创建方法,导致内存占用过多
组合继承
将 原型链继承 和 构造函数继承 组合
// 原型链继承 主要代码
Child.prototype = new Parent();
Child.prototype.construct = Child;
// 构造函数继承 主要代码
Parent.call(this, name, actions);
复制代码
function Parent(name,actions){
this.name = name;
this.actions = actions;
}
Parent.prototype.eat = function(){
console.log(`${this.name} - eat`);
}
function Child(id) {
this.id = id;
Parent.apply(this,Array.from(arguments).slice(1));
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
const child1 = new Child(1, "c1", ["hahahahahhah"]);
const child2 = new Child(2, "c2", ["xixixixixixx"]);
console.log(child1.eat === child2.eat); // true
复制代码
问题:
- 调用了两次构造函数,做了重复的操作
Parent.apply(this,Array.from(arguments).slice(1))
Child.prototype = new Parent()
寄生组合继承
主要是将 组合继承 中,调用第二次 构造函数 寄生在一个空函数上:
Child.prototype = new Parent();
// 变为:
let TempFunction = function(){}; // 空函数,调用多少次没多大关系
TempFunction.prototype = Parent.prototype;
Child.prototype = new TempFunction();
// 另一种写法:
Child.prototype = Object.create(Parent.prototype);
复制代码
提问:为什么以一定要通过桥梁的方式让 Child.prototype
访问到 Parent.prototype
,直接 Child.prototype = Parent.prototype
不行吗?
回答:不行。
注意:Child.prototype = Parent.prototype
- 在 原型链继承 中引发的问题是: Child只能继承原型上的属性方法,不能继承实例上的属性方法。
- 在 组合继承 中引发的问题是:原型的
prototype
会随着实例的prototype
改变而改变。(原型链继承中本身就存在这个问题)
圣杯模式
function inherit = (function(){
var F = function(){};
return function(Target,Origin) {
F.prototype = Origin.prototype;
Target.prototype = new F();
Target.prototype.constuctor = Target;
Target.prototype.uber = Origin.prototype;
}
}());
复制代码
class 继承
class Parent{
constructor(){
this.name = 'fj';
}
getName(){
console.log(this.name)
}
}
class Child extends Parent{
constructor(){
super()
}
}
复制代码
其他
鸡生蛋问题
Object instanceof Function // true
Function instanceof Object // true
Object instanceof Object // true
Function instanceof Function // true
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END