原型与原型链「10 分钟读懂 JS 的面向对象核心」

🚀 个人简介:某大型测绘遥感企业资深Webgis开发工程师,软件设计师(中级)、优快云优质创作者
💟 作 者:柳晓黑胡椒❣️
📝 专 栏:js基础
🌈 若有帮助,还请关注点赞收藏,不行的话我再努努力💪💪💪


JavaScript 是一门基于**原型继承(Prototype Inheritance) 的语言。
原型机制是 JS 实现
面向对象编程(OOP)**的核心基础。
理解它,不仅能更好地掌握继承与对象机制,也能更深入理解框架底层设计(如 Vue、React、Cesium 等)。

一、设计初衷:JS 的面向对象与原型思想

在没有传统类(Class)的早期 JavaScript 中,语言设计者引入了「原型链」来模拟类继承。
它的思想源自**单链表(Single Linked List)**结构,通过对象间的引用关系,实现属性与方法的逐层查找。

核心概念可以这样理解:

名称含义特点
构造函数(Constructor)创建对象的函数(例如:function Person() {}类的定义方式
原型对象(Prototype)构造函数的共享属性与方法存储处所有实例共享
原型链(Prototype Chain)实例对象通过 __proto__ 指向其所属类的原型对象实现继承机制

二、三大核心概念

https://s.poetries.work/images/20210309102100.png

原型(prototype)

每个函数都有一个属性:prototype
它指向一个对象(Object),该对象存放所有共享属性与方法。

function Person(name) {
  this.name = name
}
Person.prototype.sayHi = function() {
  console.log(`Hi, I'm ${this.name}`)
}

📌 说明:
Person.prototype 就是“Person类”的公共区域,实例都会通过原型链访问到这里。

构造函数(constructor)

每个原型对象中,都有一个属性 constructor,指向该原型所属的函数本身。

console.log(Person.prototype.constructor === Person) // true

✅ constructor 的作用:记录原型的“归属关系”,在原型重定向时尤其重要。

原型链(proto

每个对象都有一个隐藏属性:__proto__
它指向当前实例所属类的 prototype 原型对象。

const p1 = new Person("Alice")

console.log(p1.__proto__ === Person.prototype) // true
console.log(Person.prototype.__proto__ === Object.prototype) // true
console.log(Object.prototype.__proto__) // null

这就是原型链的本质:一个逐层向上的引用关系。
在这里插入图片描述

三、原型链的查找机制

当访问一个对象的属性时,JavaScript 引擎会遵循以下查找规则:

  1. 首先找自己的私有属性,私有属性有,则调取私有属性
  2. 若不存在,默认基于__proto__原型链,找所属类prototype原型对象上的公共属性和方法
  3. 如果没有,则沿着prototype原型对象的__proto__原型链继续往上找
  4. 若仍未找到,则继续向上查找,直到 Object.prototype
  5. 若到达顶层仍未找到,则返回 undefined
    在这里插入图片描述

四、万物皆对象

在 JS 中,几乎所有的值(除 undefined、null 外)都能通过 proto 追溯到 Object.prototype
因此我们说 —— 万物皆对象(Everything is Object)。

console.log([] instanceof Object) // true
console.log(() => {} instanceof Object) // true
console.log(/abc/ instanceof Object) // true

即使是数组、函数、正则、日期,它们的原型链最终都指向 Object.prototype。

五、Object.prototype.proto === null

Object.prototype 是所有对象的基类(所有对象的顶层原型)。
__proto__ 值为 null,标志着原型链的终点。

console.log(Object.prototype.__proto__) // null

这也是防止无限循环查找的机制:原型链在此处“断开”。

六、Object.create():创建带原型的对象

Object.create(proto, [propertiesObject])
🧩 作用:用于创建一个以指定原型对象为原型的新对象。
💡 说明:
第一个参数定义原型
第二个参数定义新对象的属性描述符(类似 Object.defineProperty),默认为undefined

var obj = Object.create({ a: 1 }, {
  // foo会成为所创建对象的数据属性
  b: {
    writable: true,//是否可重写
    configurable: true,//是否可枚举
    enumerable: true,//是否可删除和修改特征
    value: "hello"//属性的值
  },
  // bar会成为所创建对象的访问器属性
  c: {
    get: function () { return 10 },// 取值器
    set: function (value) { // 赋值器
      console.log("设置的值为", value);
    }
  }
})

Object.create(null)

🧩 作用:创建一个没有原型链的纯净对象(所属类的prototype原型对象为null的空对象)
📘 场景:
这种对象常用于实现 纯字典(Map-like) 结构,不会继承任何默认方法(如 toString())。

var obj = Object.create(null);
console.log(obj.prototype);//undefined  对象没有pototype这个属性
console.log(obj.__proto__);// undefined 

七、给类的原型上扩展属性方法的4种方法

序号扩展方式示例代码说明
直接扩展类原型Fn.prototype.xxx = ...最常见方式,向类的原型对象中追加方法或属性(向默认开辟的堆内存中扩展属性方法)
扩展内置类原型Object.prototype.xxx = ...慎用!会影响所有对象(全局污染风险)
基于实例原型扩展obj.__proto__.xxx = ...会修改实例的原型链,不推荐(IE 不支持)
原型重定向Fn.prototype = { constructor: Fn, ... }重建原型对象时需手动修复 constructor 指向(手动开辟一个堆内存赋值)

八、ES6 新方法:取代__proto__

ES6 引入以下两种标准方法来安全操作原型:

Object.getPrototypeOf(obj) // 取代 obj.__proto__
Object.setPrototypeOf(obj, proto) // 取代 obj.__proto__ = proto

示例:

const p = {}
const proto = { a: 1 }

Object.setPrototypeOf(p, proto)
console.log(Object.getPrototypeOf(p)) // { a: 1 }

🔍 建议始终使用这两种方法,而非直接访问 proto,以保持代码的兼容性与可维护性。

Takeaways

  • 原型机制是 JavaScript 面向对象的根基;
  • proto 链接实例与类原型;
  • prototype 是构造函数的共享区域;
  • constructor 建立类与原型的对应关系;
  • ES6 提供 Object.getPrototypeOf / Object.setPrototypeOf 安全替代方案。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柳晓黑胡椒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值