【js篇】JavaScript 原型链的终点揭秘

44 阅读3分钟

在深入理解 JavaScript 的原型机制时,一个核心问题始终萦绕在开发者心头:

“原型链的终点到底是什么?”

网上有很多说法:“是 Object.prototype”、“是 null”、“是根对象”……这些说法看似矛盾,实则各有侧重。今天,我们就来彻底搞清楚:原型链的终点究竟是什么?它为什么是 null?以及如何通过代码验证这一点。


一、前置知识:什么是原型链?

简单回顾一下:

  • 当你访问一个对象的属性时,JS 引擎会先在该对象自身查找;
  • 如果找不到,就去它的 __proto__(即原型)中查找;
  • 找不到就继续向上查找“原型的原型”;
  • 这个逐层向上查找的过程,就是 原型链(Prototype Chain)

那么,这个“向上”的过程,终点在哪里?


二、原型链的终点:null

✅ 结论先行:

原型链的终点是 null

更准确地说:

Object.prototype.__proto__ === null; // true

这意味着:Object.prototype 的原型是 null,而 null 没有任何属性和方法,也无法再向上查找。因此,查找过程在此终止


三、为什么终点是 null 而不是 Object.prototype

这是一个常见的误解。我们来澄清:

说法正确性解释
“终点是 Object.prototype❌ 不准确Object.prototype最后一个有实际属性的对象,但它仍有 __proto__,所以不是链的终点。
“终点是 null✅ 正确null 是原型链的终止标志,表示“没有更上层了”。

📌 类比理解:

想象一条家族谱系链:

你 → 父母 → 祖父母 → 曾祖父母 → ... → 某位祖先 → (无记录)
  • Object.prototype 就像“有记载的最后一位祖先”;
  • null 就像“无记录”,表示谱系到此为止。

四、代码验证:如何打印出原型链的终点?

我们可以通过以下几种方式来验证原型链的终点。

✅ 方法1:直接访问 Object.prototype.__proto__

console.log(Object.prototype.__proto__); // 输出: null
console.log(Object.prototype.__proto__ === null); // true

这是最直接的证据。


✅ 方法2:手动遍历一个对象的原型链

function Person(name) {
  this.name = name;
}

const p = new Person('Alice');

let current = p;
let depth = 0;

console.log('--- 原型链遍历 ---');
while (current !== null) {
  console.log(`Level ${depth}:`, current);
  current = Object.getPrototypeOf(current);
  depth++;
}

// 输出示例:
// Level 0: Person { name: 'Alice' }
// Level 1: { constructor: ƒ Person() }
// Level 2: { __defineGetter__: ƒ, __defineSetter__: ƒ, ... }
// Level 3: null

可以看到,最终 current 变成了 null,循环结束。


✅ 方法3:使用 isPrototypeOfgetPrototypeOf 组合验证

const obj = {};
const proto1 = Object.getPrototypeOf(obj);           // Object.prototype
const proto2 = Object.getPrototypeOf(proto1);        // null

console.log(proto1);  // Object.prototype
console.log(proto2);  // null
console.log(proto2 === null); // true

五、图解原型链结构

       p (实例)
        ↓ __proto__
Person.prototype
        ↓ __proto__
  Object.prototype
        ↓ __proto__
        null
          ↓
       停止查找
  • pPerson.prototypeObject.prototypenull
  • 当查找 toString 时,在 Object.prototype 中找到;
  • 当查找一个不存在的属性(如 nonExistent),会一路查到 null,返回 undefined

六、重要补充:Object.prototype 的特殊性

虽然 Object.prototype.__proto__ === null,但 Object.prototype 本身是一个非常特殊的存在

  • 它是所有对象的“根原型”;
  • 它提供了 toStringhasOwnPropertyisPrototypeOf 等基础方法;
  • 它是原型链中最后一个具有实际功能的对象
  • 所有对象都继承自它。

所以,说“所有对象最终都由 Object 构造”是合理的,但要理解这里的“构造”是通过原型链继承实现的,而不是字面意义上的 new Object()


七、常见误区澄清

误区正解
Object.prototype 没有原型❌ 它有原型,就是 null
null 是一个对象typeof null === 'object' 是历史 bug,null 表示“无对象”
原型链终点是 Object 构造函数❌ 终点是 nullObject 是构造函数

八、总结:关键结论

问题答案
原型链的终点是什么?null
如何验证?Object.prototype.__proto__ === null
Object.prototype 是终点吗?不是,它是最后一个有属性的对象
为什么终点是 null表示原型链终止,无法再向上查找
所有对象都继承自 Object 吗?是的,通过原型链继承

💡 结语

null 不是空,而是终点;Object.prototype 不是终点,而是最后的港湾。”

理解原型链的终点,不仅能帮你写出更健壮的代码,还能在面试中从容应对“JS 如何实现继承”这类高频问题。

记住:每一次属性查找,都是一次从实例到 null 的“向上朝圣”之旅。