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

ES5/ES6 的继承原理上有什么不同? #3

Open
CuriosityLxn opened this issue Jun 15, 2021 · 0 comments
Open

ES5/ES6 的继承原理上有什么不同? #3

CuriosityLxn opened this issue Jun 15, 2021 · 0 comments

Comments

@CuriosityLxn
Copy link
Owner

CuriosityLxn commented Jun 15, 2021

题目

ES5/ES6 的继承原理上有什么不同?

题目来源

ES 5 使用 Object.create 创建的对象

function A() {
  this.name = 'Becca';
}
A.prototype.sayHi = function() { console.log('Hi ', this.name) };     // 在 A 原型对象中添加一个方法
A.staticFun = function () { console.log('staticFun') };     // 给 A 添加一个静态方法

function B() {
  A.call(this);
  this.b = 'Hello world';
}

B.prototype = Object.create(A.prototype, {
  constructor: { value: B, writable: true, configurable: true }
});

let b = new B();
b.sayHi();     //  Hi Becca
b.staticFun();     //  Uncaught TypeError: b.staticFun is not a function

继承步骤

  1. Object.create:
    • B.prototype.proto = A. prototype; 让 B 的原型链对象的指针指向 A 的原型对象
    • B.prototype. constructor = B; 让 B 的 constructor 指向自身
  2. A.call(this):
    • 创建 B 的时候,B 就有了自己的 this,所以需要用 call 方法改变 this 指向,让 B的实例属性 继承 A的实例属性。

实例 b 的原型链如下:

image

在控制台验证原型链,

b.__proto__ === B.prototype;   // true
B.prototype.constructor === B;    // true
B.prototype.__proto__ === A.prototype;    // true

b.staticFun;    // undefined
B.staticFun;    // undefined
A.staticFun;    // ƒ () { console.log('staticFun') }

Q:为什么构造函数 B 和实例 b 都没有继承到静态方法 staticFun 呢?
A:B.__proto__ 没有指向 A.__proto__,而是指向了 Function.prototype

A.__proto__ === Function.prototype;    // true
B.__proto__ === Function.prototype;    // true
b.__proto__ === Function.prototype;    // false
b.__proto__ === B.prototype;   // true

MDN 表示,构造函数只能传递 Father.prototype 中的属性和方法给子级或者实例,而不能传递 Father. 下的属性和方法。
console 结果验证了这一点, ES 5 使用的寄生组合式继承无法自动继承父级的静态方法。

ES 6 使用 class 关键字创建的对象

ES 6 引入了一套新的关键字用来实现 class,包括 class, constructorstaticextendssuper

class A {
  constructor() {
    this.a = 'hello';
  }

  static staticFun = function () {
      console.log('staticFun')
  }
}

class B extends A {
  constructor() {
	super();
	this.b = 'world';
  }
}

let b = new B();

b.staticFun;    // undefined
B.staticFun;    // ƒ () { console.log('staticFun') }
A.staticFun;    // ƒ () { console.log('staticFun') }

继承步骤

  1. class A 通过 constructor 创建 this;
  2. class B 通过 constructor 的 super(),根据父类上的构造函数和方法,修饰自身 this。

说明 ES 6 使用的原型链继承,将自身原型链指向父级,所以可以继承父级的任何属性。

A.__proto__ === Function.prototype;    // true
B.__proto__ === Function.prototype;    // false
B.__proto__ === A;    // true

class B 的原型链:

image

super() 与 A.call(this) 实现继承时的区别

在继承原生构造函数的情况下,A.call(this) 无法获取原生构造函数的内部属性,super() 可以。

总结

  • ES5 的子类和父类的构造函数函数的原型链都指向 Function.prototype;
  • ES6 的子类的构造函数的原型链指向父类的构造函数

本篇参考

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

No branches or pull requests

1 participant