原型及原型链

new 操作符

先让我们看一段简单的代码:

function Test() {
  this.a = "a";
  this.b = "b";
}
const instance = new Test();

new 操作符做了什么?

引用MDN的说法:

  1. 创建一个空白且简单的 JavaScript 对象。

    通过new Object()创建一个空白对象。

  2. 链接该对象到另一个对象。

    为步骤 1 创建的对象添加__proto__属性指向原型。

    得到{ __proto__: Test.prototype }

    解释一下:另一个对象就是Test.prototype(原型)。

  3. 将步骤 1 创建的对象作为 this 上下文。

    this = { __proto__: Test.prototype }

    执行 Test 函数,最终this = { a: 'a', b: 'b', __proto__: Test.prototype }

  4. 如果该函数没有返回对象,则返回 this,否则返回对象

涉及上下文,这里引用俩个通俗易懂的上下文解释:中 英 。

一言以蔽之:

Context is always the value of the this keyword which is a reference to the object that “owns” the currently executing code or the function where it’s looked at.

我的理解:上下文就是执行当前代码或者函数中this关键字绑定的值。

抛砖引玉,接下来就是本文要探讨的原型和原型链。

prototype

prototype 中文名叫做原型。

重点:只有函数拥有原型

函数原型有什么用嘞?

个人理解:当通过 new 操作符创建新对象时,如果没有原型,那么我们就需要 copy 所有属性,每一个实例都这样做是浪费内存的。

而有了原型,我们就可以通过引用原型的方式共享属性(共享的属性一般为函数方法)。

举个例子:

function Test() {
  this.a = "a";
  this.b = "b";
}
const instance = new Test();
Test.prototype.c = "c";
console.log(instance.c); // 'c'

通过前面我们知道:instance = { a: 'a', b: 'b', __proto__: Test.prototype }

instance 中虽然没有 c 属性,但是仍然打印出了 instance.c 的值。

__proto__

一般用__proto__实现原型链,所有对象均存在__proto__属性(null不是对象,null没有__proto__属性)。

当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层为止(JavaScript 深入之从原型到原型链)。

以上文的 instance.c 为例,因为 instance 中没有 c 属性,所以去查找 instance.__proto__.c,即Test.prototype.c,得到了相应值。

那如果我们调用 instance.hasOwnProperty 又是怎样的呢?

以 instance 为例分析:

首先,在const instance = new Test()过程中,创建以下关系:

原型及原型链_第1张图片

之前提到,所有对象均存在__proto__属性,所以 Test.prototype 也存在__proto__属性,那么这个值是什么?

答案很简单,Test.prototype 是个对象,即通过new Object()创建,类比instance = new Test()很容易得到Test.prototype.__proto__ = Object.prototype

更新关系图如下:

原型及原型链_第2张图片

Object.__proto__ = null,所以完整原型链如下:

原型及原型链_第3张图片

补充

函数原型默认含有 constructor 指向函数本身,即:

function Test() {}
Test.prototype.constructor === Test; // true

你可能感兴趣的:(原型及原型链)