第3章 原型与对象:查找路径回放


第3章 原型与对象:查找路径回放

章节摘要:对象不是属性的口袋,而是一串节点——自己的属性放本体,公共能力放在原型上,原型又有原型,直到 null。本章逐帧回放一次属性访问的完整查找路径,再看引擎为加速这条路发明的两件工具:隐藏类(给对象定型)与内联缓存(记住上次在哪找到的),最后用同一种视角审视数组的「空洞」与元素类型,解释为什么往数字数组里塞一个字符串会让性能滑坡。读完本章,继承、 instanceof、性能形状稳定三件事会在同一张图里合流。

学习目标

阅读完本章,你应当能够:

  1. 手工推演 obj.method() 的完整查找序列:自身属性 → 原型 → 原型的原型 → null;
  2. 解释 __proto__、prototype、constructor 三个容易混淆的名词各自指向什么;
  3. 用 new 的四步动作说明实例与构造器原型之间的连接是如何建立的;
  4. 描述隐藏类的转移链与内联缓存的命中、未命中机制,写出形状稳定的对象构造代码;
  5. 判断一段数组操作会不会引发去优化或字典模式,选择合适的数组初始化方式。

核心概念速览

属性访问是一次向上攀爬:每一站先翻自己的口袋,翻不到就去上一站。class 语法、extends、instanceof 全部建立在这条攀爬路线上。

子章节导航

3.1 原型链查找路径逐帧回放

把 student.fullName 的一次访问拆成一帧帧:查本体、查 Student.prototype、查 Object.prototype、到 null 判 undefined 或 TypeError。同时理清 new 的四步动作与 instanceof 的实现原理,你会发现 class 不过是这条链的糖衣。

3.2 隐藏类与内联缓存

引擎给「形状相同」的对象共享一张隐藏类,属性访问被缓存成「按偏移量直取」。对象形状乱改会导致隐藏类转移链分叉、内联缓存失效、优化退场。这一节把引擎的加速器讲透,也给出保持形状稳定的写法清单。

3.3 数组的引擎代价

数组在引擎眼里是一块带类型的连续存储:全是小整数是一种优化形态,混入字符串就降级,挖出空洞更特殊。map、filter、reduce 的语义与代价、类数组与真数组的转换,都从「存储形态」这个视角重新讲一遍。

子章节之间的逻辑关系

三节共享同一件事的三个层面:3.1 是「查找的正确性」(沿链上溯的语义),3.2 是「查找的速度」(缓存与形状),3.3 是「查找的存储底座」(元素类型与空洞)。

一次 obj.x 访问 | +-- 语义层:3.1 沿原型链上溯,直到命中或到顶 | +-- 速度层:3.2 隐藏类定型 + 内联缓存记住上次的站 | +-- 存储层:3.3 数组场景下 x 是下标,直接映射到元素存储 ​

第 1 章流水线里的反馈向量在此落地为内联缓存;本章的形状稳定话题是第 6 章性能优化的直接前置;错误查找路径(查到 null 抛 TypeError)是第 7 章「报错解读」的素材来源。

前置知识与后续延伸

  • 前置:第 1 章执行上下文;第 2 章调用栈(方法调用时 this 由最后一层接收者决定)。
  • 为后续铺垫:隐藏类与内联缓存是第 6 章「与引擎合作」的核心论据;原型链顶端的 null 判断会在第 7 章错误排障里复用;数组的存储形态直接支撑第 6 章的性能清单。

常见疑问

问:都 2026 年了,还要学原型链吗?class 不是已经替代它了?
class 只是糖衣,链没有变——你在控制台打印任何 class 实例的原型,看到的仍是构造器的 prototype 对象。读懂原型链的理由有三个:存量代码里全是函数构造器风格;instanceof、Object.create、原型污染防护等机制仍直接操作这条链;面试与源码阅读绕不开。会用 class 写代码与理解代码怎么跑,是两层能力。

问:隐藏类是 V8 独有的吗?
概念上各家引擎都有对应机制(SpiderMonkey 的 shape、JavaScriptCore 的 structure),名字不同、思路一致:给动态对象建形状索引。所以「保持形状稳定」这条建议跨引擎通用,不是某个实现的偏好。

问:性能相关的两节(3.2、3.3)要背结论吗?
不背,记判定方法:形状是否稳定、元素是否纯净、扫描了几遍。具体数值在不同机器与引擎版本上浮动很大,但判定方法稳定。第 6 章会把这套判定方法扩展成完整清单。

问:原型与 class 的学习精力怎么分配?
写代码用 class,读代码要懂原型——两条线并行不冲突。本章把篇幅放在原型链上,因为 class 的语法表层(构造器、方法、继承关键字)在写的过程中自然就会了,而链的语义只靠写是碰不到的。读完 3.1 你应该能把任何 class 代码在脑内翻译成原型语言,这个能力在读框架源码时会持续回报。性能两节(3.2、3.3)则负责把「查找」从语义正确推进到代价可控。

学习检验

自测三题:其一,写出 student.toString() 的完整查找帧序列,直到 Object.prototype;其二,解释「先加 y 再加 x」与「先加 x 再加 y」的对象为什么在引擎眼里是两种形状,后果是什么;其三,一段「数字数组里混入一个字符串再排序」的代码,说出它降级到了哪种元素形态、大概慢多少。答得出这三题,本章的语义层、速度层、存储层就都通了。


作者与出处
原作者: 灏天文库
来源:平台策划编纂
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U