DTeam 技术日志

Doer、Delivery、Dream

谈谈 javaScript 原型链

小纪同学 Posted at — Mar 23, 2021 阅读

原型链是为了实现继承,也就是说 js 的继承是基于原型链的。

原型-prototype,是一个对象,用于存放共享的属性和方法的。

原型

原型主要有这么几个概念:

__proto__prototypeconstructor

什么是__proto__?

js 会为每个 对象 添加一个属性,这个属性指向另外一个对象的prototype,js 可以通过 Object.getPrototypeOf(obj)获取,chrome 浏览器实现为__proto__

什么是prototype?

js 会为每个 函数 添加一个prototype属性,表示自己的原型对象。 prototype是个对象。

什么是constructor?

是 js 创建和初始化对象的方法,如果没有自己指定constructor,则会默认有个空的constructor。 原型对象的constructor指向自己的创造者,每个原型对象都有constructor。所有对象都会从它的原型上继承 constructor 属性。

Tips:

  1. 函数也是对象,所以函数也有 __proto__ 属性。
  2. 规定 Object.prototype.__proto__ === null
  3. 默认情况下,除 Object 函数的 prototype.__proto__ 都是 Object.prototype
  4. Object 函数的 __proto__ 永远指向 prototype

⚠️ 注意:这里有个特殊的函数: Function,任何函数都是 Function 的实例,包括 Object。所以 Function 可以说是根构造函数。

所以 Object.__proto__ 就是 Function.prototype

所以 Function.__proto__ 也是 Function.prototype

image.png

以上就是主要知识点,为了理解咱们举个 🌰:

创建一个普普通通的函数 A

function A() {}

此时 A 里面有prototype,__proto__两个属性。 A 同时继承了 A.prototype.constructor

A.prototype

A.prototype 就是它的原型对象,里面有什么?

constructor__proto__,为什么会有__proto__

因为 prototype 也是个对象。

A.prototype.constructor 指向了谁?

当然是 Aprototype里面的constructor指向它的函数。

A.prototype.__proto__指向了谁?

当然是 Object.prototype,因为 默认情况下,任何函数的原型属性__proto__ 都是 Object.prototype

image.png image.png

A.__proto__

A.__proto__是什么?

应该知道它指向一个 prototype,那么是谁的 prototype

当然是 Function 的。因为它也是由 Function 创建的。__proto__ 是由浏览器实现的,不是标准写法,Object 提供了获取原型的方法:

image.png image.png image.png

A.constructor

A.constructor,实际是 A.prototype.constructor,指向自己的创造者:Function

image.png

原型链

创建一个 A 的实例:

a = new A();

根据上面讲述,a 会有 __proto__constructor两个属性,并且 a.__proto__ === A.prototype

a.constructora.__proto__.constructor

image.png

image.png

如果这个时候 A.prototype 中如果有属性,或者方法,a 都是可以调用的。 image.png

image.png

两个对象通过 __proto__ 连接,就组成了原型链。

可以给对象指定原型(不建议这么做),这里举例仅是为了理解原型链。将 A 的实例赋值给 B 的原型,这样可以理解为 B 继承了 AB 创建的实例 b 也可以调用 A 原型中的方法了: image.png

整体结构图如下: image.png

从上面例子可以看出 js 创建一个对象(使用 new 操作符)大致过程:

  1. 创建一个对象
  2. 给它一个原型
  3. 把对象放进 constructor 加工

创建一个对象: image.png

<!-- new 一个 A 对象  -->
function newA(...args) {
  var self = Object.create(A.prototype)
  var res = A.prototype.constructor.call(self, ...args)
  if (typeof res === 'object' && res !== null) {
    return res
  }
  return self
}

应用与总结

Array 中的 forEachfindfilter 等都是在 Array.prototype 上,这样的内置对象还有很多。

es6 实现了 class 语法糖,实际还是应用原型链。

// function A(name) {
//   this.name = name;
// }

// A.prototype.run = function() {
//   console.log(`${this.name} running...`);
// };

class A {
  constructor(name) {
    this.name = name;
  }

  run() {
    console.log(`${this.name} running...`);
  }
}

但是不建议修改内置对象的原型,会产生一些副作用,比如: image.png image.png

觉得有帮助的话,不妨考虑购买付费文章来支持我们 🙂 :

付费文章

友情链接