Skip to content
文档章节

原型链和继承

JS 的继承是基于原型的,即使是 ES6 增加的 class 字段,也是原型的语法糖。

参考: MDN 继承

当谈到继承,JS 就只有一种数据结构 Object, 几乎所有的 JS 对象都是最顶端 Object 的实例。

原型链继承

原理: 每个对象objA 都有一个私有属性__proto__ 指向 构造函数FuncA 的原型对象 prototype, 即 FuncA.prototype, 而该原型对象又有自己的原型对象 __proto__, 层层向上知道一个对象的原型是 null, 如此形成了原型链。

js
function FuncA() {console.log('FuncA')};

var objA = new FuncA();

objA.__proto__ === FuncA.prototype;

FuncA.prototype.__proto__ === Object.prototype;

Object.prototype.__proto__ === null;

proto

原型链继承属性

JS对象 obj 访问属性 p , 会从自身查找,如果没有属性,会在其原型链上查找,直到找到属性p, 或者找到原型链顶端。

js
function FuncA() {
  this.a = 1;
  this.b = 2;
}

const o = new FuncA();

console.log(o.a); // 1;

// 在原型链上定义属性
FuncA.prototype.b = 3;
FuncA.prototype.c = 4;

// {a: 1, b: 2} --> {b: 3, c: 4} --> Object.prototype --> null

// 自身属性,屏蔽原型链上属性 b
console.log(o.b); // 2;

// 原型链上查找到属性
console.log(o.c); // 4

// 自身和原型链上查找不到的属性
console.log(o.d); // undefined

上面的 原型链是 {a: 1, b: 2} --> {b: 3, c: 4} --> Object.prototype --> null

原型链继承方法

JS 中函数 FuncA 有一个默认属性 prototype, 其中 FuncA() 称作构造函数, FuncA.prototype.constructor 指向 FuncA()

和属性继承一样,方法也可以继承,注意其中的 this 指向。

js
FuncA.prototype.print = function () {
  console.log(this.b);
};

o.print(); // 2
FuncA.prototype.print(); // 3

常见对象和生成原型链

S 语法中创建对象

js
var o =  {a: 1}
// o --> Object.prototype --> null

var arr = []

// arr --> Array.prototype --> Object.prototype --> null

function FuncA() {

}
var f = new FuncA();

// f --> FuncA.prototype --> Function.prototype --> Object.prototype --> null

构造器 prototype

js
function FuncB() {
  this.a = 1;
}

FuncB.prototype = {
  print() {
    console.log(this.a);
  },
};

const b = new FuncB();

console.log(b.print());

Object.create 创建对象

建议开发中使用 Object.create 替换掉使用 __proto__ 属性

js
const c = Object.create({ m: 1 });

// c --> {m: 1} --> Object.prototype --> null

console.log(c);
console.log(c.m);

使用Class

js
"use strict";

class Polygon {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

class Square extends Polygon {
  constructor(sideLength) {
    super(sideLength, sideLength);
  }
  get area() {
    return this.height * this.width;
  }
  set sideLength(newLength) {
    this.height = newLength;
    this.width = newLength;
  }
}

var square = new Square(2);