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
相关推荐
草履虫建模13 小时前
力扣算法 1768. 交替合并字符串
java·开发语言·算法·leetcode·职场和发展·idea·基础
naruto_lnq15 小时前
分布式系统安全通信
开发语言·c++·算法
Mr Xu_16 小时前
告别冗长 switch-case:Vue 项目中基于映射表的优雅路由数据匹配方案
前端·javascript·vue.js
前端摸鱼匠16 小时前
Vue 3 的toRefs保持响应性:讲解toRefs在解构响应式对象时的作用
前端·javascript·vue.js·前端框架·ecmascript
学嵌入式的小杨同学16 小时前
【Linux 封神之路】信号编程全解析:从信号基础到 MP3 播放器实战(含核心 API 与避坑指南)
java·linux·c语言·开发语言·vscode·vim·ux
sleeppingfrog16 小时前
zebra通过zpl语言实现中文打印(二)
javascript
Re.不晚16 小时前
Java入门17——异常
java·开发语言
精彩极了吧16 小时前
C语言基本语法-自定义类型:结构体&联合体&枚举
c语言·开发语言·枚举·结构体·内存对齐·位段·联合
南极星100517 小时前
蓝桥杯JAVA--启蒙之路(十)class版本 模块
java·开发语言
未来之窗软件服务18 小时前
未来之窗昭和仙君(六十五)Vue与跨地区多部门开发—东方仙盟练气
前端·javascript·vue.js·仙盟创梦ide·东方仙盟·昭和仙君