请解释 JavaScript 中的原型 (Prototype) 和原型链 (Prototype Chain) 的概念。

推荐答案

JavaScript 中,每个对象都有一个原型(prototype)属性,这个属性本身也是一个对象。当我们访问对象的属性时,如果对象本身没有这个属性,JavaScript 引擎会沿着对象的原型链向上查找,直到找到该属性或到达原型链的末端(null)。

原型 (Prototype):

  • 每个函数(包括构造函数)都有一个 prototype 属性,这个属性指向一个对象,这个对象通常被称为原型对象。
  • 当使用 new 关键字调用构造函数创建对象时,新创建的对象的内部属性 [[Prototype]](可以通过 __proto__Object.getPrototypeOf() 访问)会指向构造函数的 prototype 属性。
  • 原型对象的作用是允许该构造函数创建的所有实例对象共享属性和方法。

原型链 (Prototype Chain):

  • 原型链是指对象通过 [[Prototype]]__proto__)属性链接起来的一系列原型对象。
  • 当访问对象的属性或方法时,如果对象自身没有,就会沿着原型链向上查找,直到找到或者到达原型链的末端(null)。
  • 原型链的末端通常是 Object.prototype,它的 [[Prototype]] 属性为 null
  • 原型链是实现 JavaScript 继承的基础机制。

本题详细解读

1. 深入理解 Prototype

函数的 prototype 属性

在 JavaScript 中,函数也是对象。每个函数都有一个特殊的属性叫做 prototype。这个 prototype 属性是一个对象,默认情况下,它有一个 constructor 属性,指向该函数自身。

原型对象的作用

当使用 new 关键字调用构造函数创建一个新的对象实例时,这个新实例的内部会有一个隐藏属性 [[Prototype]] (可以通过 __proto__ 或者 Object.getPrototypeOf() 访问),该属性指向构造函数的 prototype 属性。这意味着,通过构造函数创建的所有实例都会继承原型对象上的属性和方法。

-- -------------------- ---- -------
-------- ------------ -
  --------- - -----
-

------------------------- - ---------- -
  ------------------- -- ---- -- - - -----------
--

--- ------- - --- ----------------
--- ------- - --- --------------

------------------- -- -- ------- -- ---- -- ------
------------------- -- -- ------- -- ---- -- ----

----------------------------- --- ------------------ -- -- ----
----------------------------- --- ------------------ -- -- ----

在这个例子中,person1person2 实例都没有 sayHello 方法,但他们通过原型链都能够访问到 Person.prototype 上的 sayHello 方法。这就是原型继承。

2. 深入理解 Prototype Chain

原型链的形成

原型链是多个对象通过 [[Prototype]] 属性链接形成的链条。每个对象的 [[Prototype]] 属性指向其原型对象,而原型对象自身也可能有原型,依此类推。

-- -------------------- ---- -------
-------- ------------ -
    --------- - -----
-
-------------------- - -----------
  ------------------- ------
-
-------- --------- ------ -
    -----------------------
    ---------- - ------
-
------------- - --------------------------------
------------------------- - ----
------------------ - -----------
    ---------------------
-

--- ----- - --- ------------ ------- ------------
-----------------------------
---------------------------------------
-------------------------------------------------

----------------------- ---
-----------------------
----------------- ---------- ------- ------
----------------- ---------- ---------- ------

这里 myDog 实例的 [[Prototype]] 指向 Dog.prototype,而 Dog.prototype[[Prototype]] 指向 Animal.prototype, Animal.prototype[[Prototype]] 指向 Object.prototype。最终 Object.prototype[[Prototype]] 指向 null,原型链到此结束。

属性查找机制

当我们尝试访问对象的属性时,JavaScript 引擎会按照以下步骤查找:

  1. 首先检查对象自身是否拥有该属性。
  2. 如果没有,检查对象的 [[Prototype]] 指向的原型对象是否存在该属性。
  3. 如果原型对象仍然没有,继续查找原型对象的原型,依此类推,直到找到该属性或达到原型链的末端 null
  4. 如果到原型链的末端仍未找到该属性,则返回 undefined

这就是原型链的核心机制,使得 JavaScript 可以实现继承和代码复用。

Object.prototype 和 null

所有的 JavaScript 对象都继承自 Object.prototype,因此 Object.prototype 是原型链的最顶端。Object.prototype 本身的 [[Prototype]]null,这意味着它不继承任何对象,它标志着原型链的结束。

纠错
反馈