Skip to main content

JavaScript继承

· 2 min read
Lex
非著名前端开发

每个函数都会创建一个 prototype 属性,这个属性是一个对象,包含应该由特定引用类型的实例共享的属性和方法。实际上,这个对象就是通过调用构造函数创建的对象的原型。

默认情况下,所有原型对象自动获得一个名为 constructor 的属性,指回与之关联的构造函数。

原型链#

const Fn = function () {};Fn.prototype.name = "Lex";Fn.prototype.hobbies = ["Coding", "JavaScript", "Eating"];Fn.prototype.sayHi = function () {  console.log("Hello,World");};
const o = new Fn();o.hobbies.push("Gaming");const obj = new Fn();console.log(obj.hobbies); // [ 'Coding', 'JavaScript', 'Eating', 'Gaming' ]

盗用数据结构#

包含引用值的原型链继承导致 👆 问题,而且不能在实例化时给父类构造函数传参。

const Father = function (name) {  this.name = name;  this.sayHi = function () {    console.log(`Hello ${this.name}`);  };};Father.prototype.sayHey = function () {  console.log(`Hey Lex`);};
const Son = function () {  Father.call(this, "Alex");};
const s1 = new Son();console.log(s1.name); // Alexconsole.log(s1.sayHi()); // undefinedconsole.log(s1.sayHey()); // TypeError not a function

原理就是在实例化时调用父类构造函数,形成独立的子函数 context,因此函数在执行时不能复用(每个 instance 都要重新声明 methods)。

组合#

思路是通过盗用构造函数继承实例属性,使用原型链继承原型上的属性和方法。

warning
// 继承方法Son.prototype = new Father();

原型式继承#

利用 Object.create() API

function object(o) {  function F() {}  F.prototype = o;  return new F();}

Object.create() 本质是原型式继承的规范封装。

const person = {  name: "Lex",  hobbies: ["sleeping", "eating", "coding"],};
const anotherPerson = Object.create(person);anotherPerson.name = "bb";anotherPerson.hobbies.push("film");console.log(anotherPerson.hobbies);

属性中包含的引用值始终会在相关对象间共享,跟使用原型模式是一样的。

寄生式继承#

function createAnother(original) {  let clone = object(original); // 通过调用函数创建一个新对象  clone.sayHi = function () {    // 以某种方式增强这个对象    console.log("hi");  };  return clone; // 返回这个对象}

显然,增强的 methods 依然无法复用。

寄生式组合#

最佳实践

function inheritPrototype(subType, superType) {  let prototype = object(superType.prototype); // 创建对象  prototype.constructor = subType; // 增强对象  subType.prototype = prototype; // 赋值对象}
function SuperType(name) {  this.name = name;  this.colors = ["red", "blue", "green"];}SuperType.prototype.sayName = function () {  console.log(this.name);};function SubType(name, age) {  SuperType.call(this, name);  this.age = age;}inheritPrototype(SubType, SuperType);SubType.prototype.sayAge = function () {  console.log(this.age);};