Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

深入继承:一步步捋清五种继承方式 #3

Open
amandakelake opened this issue Feb 2, 2018 · 5 comments
Open

深入继承:一步步捋清五种继承方式 #3

amandakelake opened this issue Feb 2, 2018 · 5 comments

Comments

@amandakelake
Copy link
Owner

amandakelake commented Feb 2, 2018

总览

c5925056-aa27-4b97-9f5d-2ec786ea5125

一、借助构造函数

function Parent1() {
  this.name = 'parent1'
}
function Child1() {
  // 将父类的执行上下文指向子类,父类执行时的实例属性都会指向子类
  Parent1.call(this);// apply
  this.type = 'child1'
}

缺点

子类没有继承父类的原型方法
只继承了父类构造函数中的属性和方法

Parent1.prototype.method = (arg) => console.log(arg);
console.log(new Child1().method); // undefined

二、借助原型链

function Parent2() {
  this.name = 'parent2';
  this.arr = [1, 2, 3];
  this.method = (arg) => console.log(arg)
}
function Child2() {
  this.type = 'child2'
}
Child2.prototype = new Parent2();

原型图如下
f9311957-d401-4bc0-961b-65f3f49d65ea

缺点

引用类型的属性被所有实例共享,实例之间会互相影响

let c21 = new Child2();
let c22 = new Child2();

c21.arr.push(4);
console.log(c21.arr, c22.arr);
// 注意,下面是直接给实例添加method属性
// 只是修改了method指针,没有修改原型链上的method方法
// 只有修改引用对象才是真正的修改
c21.method = 'c21';
console.log(Parent2);
console.log(c21, c22);

c79f3ffe-030d-4753-9f32-361a2dffb9d2

三、组合(构造+原型链)

function Parent3() {
  this.name = 'parent3';
  this.arr = [1, 2, 3]
}
function Child3() {
  Parent3.call(this);
  this.type = 'child3'
}
Child3.prototype = new Parent3();

优点

每个实例不会再互相影响

缺点

实例化时,父类被构造了两次,这没有必要
call一次,new一次

四、组合优化一

function Parent4() {
  this.name = 'parent4';
  this.arr = [1, 2, 3]
}
function Child4() {
  Parent4.call(this);
  this.type = 'child4'
}
Child4.prototype = Parent4.prototype;

3dcc9c3e-5e1d-45bc-bcb5-72aaea635cc2

缺点

无法判断实例的构造函数是父类还是子类

let c41 = new Child4();
let c42 = new Child4();
console.log(c41 instanceof Child4, c41 instanceof Parent4);
// true true

但其实,构造函数就是父类本身

console.log(c41.constructor); // Parent4

很难得才通过Parent4.call(this)改变了构造函数的指向,现在又改回去了?天……不想看下去了行不行,兄dei,坚持一会就是胜利,别打瞌睡

Child4.prototype = Parent4.prototype只是把Child4prototype属性指针指向了Parent4.prototype这个引用对象而已,实际上Parent4.prototype.constructor = Parent4,这里说的有点绕,可以结合图好好理解一下
af779508-30f5-43ea-8af8-ff25a308ccf9

五、组合优化二

Object.create请先移步
Object.create() - JavaScript | MDN

function Parent5() {
  this.name = 'parent5';
  this.arr = [1, 2, 3]
}
function Child5() {
  Parent5.call(this);
  this.type = 'child5'
}
// 组成原型链
Child5.prototype = Object.create(Parent5.prototype);

但是,这时候,实例对象的constructor依然是Parent5

f611911f-9fc1-4ff8-8da6-eb7874eeb335

所以需要重新指定实例对象的构造器

Child5.prototype.constructor = Child5;

Good !

等下,还是验证一下吧

let c51 = new Child5();
let c52 = new Parent5();
console.log(c51 instanceof Child5, c51 instanceof Parent5);
console.log(c52 instanceof Child5, c52 instanceof Parent5);
console.log(c51.constructor, c52.constructor);
// true true
// false true
// Child5 Parent5

So perfect !

后记

感谢您耐心看到这里,希望有所收获!

如果不是很忙的话,麻烦点个star⭐【Github博客传送门】,举手之劳,却是对作者莫大的鼓励。

我在学习过程中喜欢做记录,分享的是自己在前端之路上的一些积累和思考,希望能跟大家一起交流与进步,更多文章请看【amandakelake的Github博客】

参考
继承与原型链 - JavaScript | MDN
JavaScript inheritance by example by Dr.Axel
Vjeux » Javascript – How Prototypal Inheritance really works
How To Work with Prototypes and Inheritance in JavaScript | DigitalOcean

@amandakelake amandakelake changed the title # 面向对象总结(构造、原型、继承、封装) 面向对象总结(构造、原型、继承、封装) Feb 11, 2018
@amandakelake amandakelake changed the title 面向对象总结(构造、原型、继承、封装) 面向对象总结 Mar 29, 2018
@amandakelake amandakelake changed the title 面向对象总结 深入继承:一步步捋清五种继承方式 Apr 14, 2018
@yanguoyu
Copy link

第四种有问题吧,Child4.prototype不能拓展了,不能在Child4的原型上新增方法,新增方法会影响到Parent4.
image

@amandakelake
Copy link
Owner Author

@yanguoyu 第四种方法本来就有这个问题,所以才会出现方法五,我上面解释了,你再认真看一下

@yanguoyu
Copy link

哦,了解。

@jefferyE
Copy link

image
这个图有点问题吧,new Parent2()的constructor不是Child2,而是Parent2
image

@nameRoy
Copy link

nameRoy commented Sep 13, 2019

我觉得最后一个图有误,组合继承调用两次,第一次是继承原型,第二次继承实例,Object.create(父原型)不就是建立一个父原型的一个副本么?子的原型为什么指向父的构造函数呢?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants