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
相关推荐
离离茶1 小时前
【笔记1-11】Qt 关闭QToolbar的拓展菜单
开发语言·笔记·qt
曹牧2 小时前
C#:窗体构造函数无法引用窗体控件
开发语言·c#
xb11322 小时前
C#使用Cancellation来取消异步任务
开发语言·c#
m0_748229992 小时前
C与C#:编程语言的核心差异解析
c语言·开发语言·c#
Mr Xu_2 小时前
Vue3 + Element Plus 实战:App 版本管理后台——动态生成下载二维码与封装文件上传
前端·javascript·vue.js
java1234_小锋2 小时前
Java中读写锁的应用场景是什么?
java·开发语言
比特森林探险记2 小时前
Vue基础语法与响应式系统详解
前端·javascript·vue.js
yong99902 小时前
MATLAB的智能扫地机器人工作过程仿真
开发语言·matlab·机器人