JavaScript 原型、原型链与原型继承的核心机制解析

文章目录

  • [原型 (prototype)、原型链 (prototype chain) 、原型继承 (prototypal inheritance)](#原型 (prototype)、原型链 (prototype chain) 、原型继承 (prototypal inheritance))

原型 (prototype)、原型链 (prototype chain) 、原型继承 (prototypal inheritance)

1.原型是什么?

在 JavaScript 中,每个对象都包含了一个 [[Prototype]] 内部隐藏属性,这个属性对应到的就是该对象的原型 (prototype) ,值有可能是 null 或是指向另一个对象。但因为 [[Prototype]] 是内部属性并无法直接被访问到,所以浏览器提供了__proto__ 的访问方法,可参考以下代码。

但要注意, __proto__ 方法并不在 ECMAScript 规范中,实际上开发中要取得对象的原型会使用 Object.getPrototypeOf

__proto__ 方法这是一个历史遗留的坑

参考代码如下:

javascript 复制代码
// Person 是一个构造函数
function Person(){}
//通过 Person 构造函数南湖,创建一个 personA对象
const personA=new Person();

//通过__proto__方法,查看 personA 的原型
console.log(personA.__proto__);

//给 Person 的原型增加一个属性sayHi
Person.prototype.sayHi =function(){
    console.log('hi')
}
console.log(personA.__proto__);

//personA通过原型链"链接"到了 Person.prototype
console.log(personA.__proto__===Person.prototype) 

// 使用 Object.getPrototypeOf API 查看原型,和__proto__方法所等价的
console.log(Object.getPrototypeOf(personA))

nodejs 环境输出如下:

javascript 复制代码
{}
{ sayHi: [Function (anonymous)] }
true
{ sayHi: [Function (anonymous)] }

因为 nodejs 环境下只会输出可枚举属性,所以第一个只输出{},而不是浏览器中看到的{constructor: ƒ}

2.\[Prototype] 又是什么? 和__proto__ 的差別是什么?

上面第一個問題已有提到,[[Prototype]] 是在 JavaScript 中物件的特殊隱藏屬性,但因為無法直接被訪問到,因此可以透過 __proto__ 的訪問方法。

3.proto 属性和 prototype属性的差別是什麼?

__proto__和prototype 是不同的属性。

  • __proto__是"每一个对象上的属性",它指向的是这个对象的"原型对象",也就是规范里的 \[Prototype]。

  • prototype 是"构造函数"上的属性,用来指定,将来 new 出来的示例,他们的原型是谁

  • 它们两个会指向同一个地方,这个地方就叫做原型对象

javascript 复制代码
// Person 是一個構造函式
function Person() {}
// 透過 Person 構造函式,創建了一個 personA 對象
const personA = new Person();

personA.__proto__ === Person.prototype; // true

4.原型链是什么?

原型对象(\[Prototype])本身是一个对象,因此它也拥有自己的原型。当我们试图访问某个对象的属性时,如果该对象没有所需的属性,它会在其原型 (prototype) 中寻找。如果原型 (prototype) 中仍然没有找到,它将会继续往上一层查找,直到找到,或者到 null 为止。这条连续的路径被称为原型链 (prototype chain) ,;链的终点值为 null

javascript 复制代码
personA.__proto__.__proto__.__proto__ === null;

例如,我們经常使用数组的 filter 方法。假设现在有一个数组 「list」,我们在这个数组上使用 filter 方法。但事实上,filter 方法并不存在于这个 list,它存在于 Array 这个构造函数上。我们今天能使用 filter 方法,也是通过原型链 (prototype chain) 实现的。

5.什么是原型链继承?

假设有一个对象 「animal」,这个对象拥有自己的属性和方法。同时我们又想建立两个基于 「animal」 的对象,分別为「cat」和「dog」,这两个对象会有一些独特的方法和属性,但同时又需要用到「animal」对象的方法和属性。在 JavaScript 里,不需要通过复制或重新实现,就可以通过原型继承(Prototypal inheritance) 达成这个目的。

简而言之,「cat」和「dog」对象本身虽然没有「animal」对象的方法,但可以从他们的原型中继承方法来使用。实际操作上,我们会将属性或方法加到原型 (prototype) 上,那么所有从这个对象中实例出来的对象,都有办法使用这个方法或属性。

javascript 复制代码
// 构造函数 Animal
function Animal() {}

// 实例
const cat = new Animal();

// 往原型对象加上方法
Animal.prototype.sleep = function () {
  console.log("sleep");
};

// 使用构造函数的 prototype 的方法
cat.sleep(); // sleep
相关推荐
zmzb0103几秒前
C++课后习题训练记录Day176
开发语言·c++
Rabitebla5 分钟前
C++ STL 之 set 详解:从底层红黑树到实际应用
开发语言·数据结构·c++·算法·leetcode
520拼好饭被践踏8 分钟前
JAVA+Agent学习day26
java·开发语言·数据结构·学习·agent
1570925113426 分钟前
优先队列:从Java源码到实战
开发语言·python
jinyishu_1 小时前
C++继承与多态进阶
开发语言·c++·程序人生
程序猿编码1 小时前
用 C++ 从零写一个能训练的 GPT:标量自动微分 + Arena 内存池
开发语言·c++·gpt·transformer·模型推理
mONESY1 小时前
React + TypeScript 入门到进阶:从 Props 类型约束到状态管理与副作用最佳实践
javascript
小灰灰搞电子1 小时前
Qt 队列容器 QQueue 的详解与示例
开发语言·qt·qqueue
码哥DFS2 小时前
算法练习day1-备战2027届秋招
前端·javascript·数据结构·算法
张元清2 小时前
React useInfiniteScroll Hook:无限滚动轻松实现(2026)
javascript·react.js