尧图精选

tech-interview-for-developer:JavaScript Object Prototype 原型机制与原型链深度解析

🕒 发布时间:2026/10/2 13:36:04 📁 来源:尧图网络
教程知识库【免费下载链接】tech-interview-for-developer 신입 개발자 전공 지식 기술 면접 백과사전 项目地址https://gitcode.com/GitHub_Trending/te/tech-interview-for-developer点击查看免费下载本篇文章面向准备技术面试的 JavaScript 开发者基于 tech-interview-for-developer 仓库中 [Language/[Javasript] Object Prototype.md](Language/[Javasript] Object Prototype.md) 一篇展开。Prototype原型是 JavaScript 对象从其他对象继承属性与方法的底层机制也是面试中常被追问的 prototype-based language、prototype chain、__proto__与prototype的区别 等问题的核心。读完本文你将理解原型对象与原型链的运作方式、new实例化背后的属性查找流程并能把原型机制正确应用到基于构造函数的对象设计中例如将方法放在 prototype 上以节省内存同时掌握与 Closure、ES2015 语法 等知识点的关联。一、什么是 Prototype为什么 JavaScript 被称为 prototype-based language1.1 原型是 JavaScript 对象间继承的机制简单来说Prototype 是 JavaScript 对象从另一个对象继承inherit属性的机制。它不依赖class/extends关键字而是通过对象与对象之间的关联来实现复用与继承。1.2 prototype-based language 的含义JavaScript 经常被描述为prototype-based language。这类语言的特点如下语言本身就支持继承inheritance每个对象都拥有一个prototype object原型对象原型对象相当于一个template object模板对象其他对象可以从它那里继承共享method方法和 property属性。也就是说JavaScript 的“继承”并非类与类之间的层级而是“实例对象 → 原型对象”的链式关联。1.3 prototype chain原型链关键点在于对象的 prototype object 本身也是一个对象它同样拥有自己的 prototype object这种层层向上的关联被称为prototype chain原型链。原型链的顶端是Object.prototype而Object.prototype的原型是null因此原型链是一条有限链路这正是后续属性查找能“走到尽头”的原因。1.4 连接发生在哪里在 JavaScript 中连接link是在 object instance对象实例与 prototype 之间建立的具体通过两种属性体现__proto__属性实例对象上指向其原型对象的内部属性[[Prototype]]的浏览器可访问形式constructor构造函数的prototype属性构造函数本身持有的、供new出来的实例共享的原型对象。面试易错点实例对象通过__proto__访问原型而函数对象通过prototype持有“将来实例共享的原型对象”。两者指向的是同一个对象但所在位置不同。现代代码更推荐用Object.getPrototypeOf()读取原型而不是直接依赖__proto__。二、理解原型对象从构造函数到实例2.1 定义构造函数看下面的示例原文档中的核心示例function Person(first, last, age, gender, interests) { // property and method definitions this.name { first: first, last : last }; this.age age; this.gender gender; //...see link in summary above for full definition }这里Person是一个普通函数但我们用new来调用它时它就扮演**构造函数constructor**的角色this指向新创建的实例实例上的name、age、gender等属性被逐个初始化同时JavaScript 引擎会建立「实例 →Person.prototype」的原型关联。2.2 创建对象实例let person1 new Person(Bob, Smith, 32, male, [music, skiing]);执行new Person(...)时引擎实际完成四件事可以从语言规范与常见 polyfill 实现推断创建一个新的空对象将该对象的原型__proto__/[[Prototype]]指向Person.prototype以该对象为this调用Person函数体初始化属性如果构造函数返回对象则返回该对象否则返回新建的实例对象。因此person1拥有自己的name、age、gender、interests属性同时通过原型链可以访问到Person.prototype上的一切成员。三、属性查找调用 person1.valueOf() 时到底发生了什么这是理解原型链最直观的实验。假设我们调用person1.valueOf()valueOf()并没有定义在Person构造函数里为什么调用不会报错按原文档给出的查找流程引擎的解析过程如下先检查实例自身浏览器首先检查person1这个 object 自身是否拥有valueOf()方法即检查它是否定义在构造函数Person()中再检查原型对象实例自身没有就检查person1的 prototype object即Person.prototype上是否有该方法沿原型链逐级上溯如果 prototype object 上也没有就继续检查它的 prototype object即原型对象的原型对象一直向上查找直到某个 prototype object 为null为止若整条链上都找不到则返回undefined调用时会抛出TypeError。在这个例子中valueOf最终会在Object.prototype上被找到并执行因为它一路从Person.prototype查到Object.prototype。这也是为什么“所有对象都能调用toString、valueOf、hasOwnProperty等通用方法”——它们都定义在原型链顶端的Object.prototype上。这个查找过程可以用一句话总结属性访问总是先查自身own property查不到就沿原型链向上逐级查找。判断属性是“自身属性”还是“继承属性”可以用Object.prototype.hasOwnProperty()精确区分。四、用 hasOwnProperty 验证原型链配合 Closure 篇中的编程思路可以用下面的代码实际验证上面描述的原型链行为function Person(first, last, age) { this.name { first, last }; this.age age; } let person1 new Person(Bob, Smith, 32); console.log(person1.hasOwnProperty(name)); // true —— 自身属性 console.log(person1.hasOwnProperty(valueOf));// false —— 继承自 Object.prototype console.log(valueOf in person1); // true —— 原型链上可以访问到 console.log(person1.__proto__ Person.prototype); // true console.log(Person.prototype.__proto__ Object.prototype); // true console.log(Object.prototype.__proto__); // null —— 原型链终点输出清晰地印证了三点name是person1的自身属性valueOf不是自身属性但通过原型链可以访问in运算符会沿链查找原型链终点确实是null。五、原型机制的实际应用把方法放到 prototype 上5.1 为什么要把方法放在 prototype 上在 Closure 一文的 Performance consideration 小节中明确指出当不需要 closure 时创建 closure 会对内存和速度造成负面影响。创建新的 object/class 时method 应该放在 object 的 prototype 上而不是 constructor 中因为constructor 每次被调用时 method 都会被重新赋值reassign。也就是说如果每个实例都持有自己的函数副本会造成不必要的内存开销而把方法定义在Person.prototype上所有实例共享同一个函数只需一份内存。5.2 反例方法定义在构造函数里function MyObject(name, message) { this.name name.toString(); this.message message.toString(); this.getName function() { return this.name; }; this.getMessage function() { return this.message; }; }上面的getName与getMessage在构造函数每次被调用时都会重新创建一遍new MyObject()生成 100 个实例就会有 100 份同名函数浪费内存。5.3 正确做法方法定义在 prototype 上function MyObject(name, message) { this.name name.toString(); this.message message.toString(); } MyObject.prototype { getName: function() { return this.name; }, getMessage: function() { return this.message; } };5.4 更稳妥的写法逐个挂到 prototype 上原文档同时提醒把整个 prototype 重新声明全部覆盖并不是推荐做法因为这会切断默认的constructor指向。更稳妥的方式是逐个向原型对象添加方法function MyObject(name, message) { this.name name.toString(); this.message message.toString(); } MyObject.prototype.getName function() { return this.name; }; MyObject.prototype.getMessage function() { return this.message; };5.5 计数器示例从 closure 版到 prototype 版Closure 篇给出了一个非常完整的对照先是一个基于 closure / IIFE 的计数器每次调用工厂函数都会新建increment、decrement、value三个函数产生额外开销随后给出了推荐的原型版实现function makeCounter() { this.publicCounter 0; } makeCounter.prototype { changeBy : function(val) { this.publicCounter val; }, increment : function() { this.changeBy(1); }, decrement : function() { this.changeBy(-1); }, value : function() { return this.publicCounter; } } var counter1 new makeCounter(); var counter2 new makeCounter(); alert(counter1.value()); // 0. counter1.increment(); counter1.increment(); alert(counter1.value()); // 2. counter1.decrement(); alert(counter1.value()); // 1. alert(counter2.value()); // 0.这里的思路正是本篇文章所讲的原型机制makeCounter是构造函数this.publicCounter是每个实例自己的状态changeBy、increment、decrement、value全部定义在makeCounter.prototype上被counter1、counter2共享两个实例的状态互不影响但方法只有一份。六、与 ES2015 的衔接class 语法是原型机制的语法糖在 ES2015 요약 정리 一篇介绍 ES2015 新增语法的背景下可以这样理解现代写法ES2015 引入的class语法本质上是基于原型机制的语法糖class中声明的方法最终仍会被放到构造函数的prototype对象上extends实现的继承底层仍是原型链。因此理解本文的 prototype 机制是正确理解class、super、Object.create、Object.setPrototypeOf等现代特性的前提。七、面试常见追问速查问题答案要点什么是 prototype-based language通过对象与原型对象之间的关联实现继承的语言原型对象是共享方法/属性的模板对象什么是 prototype chain对象 → 其原型对象 → 原型的原型…逐级向上直到null的链式结构__proto__与prototype的区别__proto__是实例指向原型的内部属性prototype是构造函数持有、供实例共享的原型对象属性查找的顺序先查自身属性再沿原型链逐级向上查到null为止为什么所有对象都有valueOf因为原型链顶端Object.prototype上定义了这些通用方法方法应定义在构造函数里还是 prototype 上定义在 prototype 上避免每次实例化都重新创建函数、浪费内存八、延伸阅读[Language/[Javascript] Closure.md](Language/[Javascript] Closure.md)闭包机制、性能考量与把方法迁移到 prototype 上的完整对照示例[Language/[Javascript] ES2015 요약 정리.md](Language/[Javascript] ES2015 요약 정리.md)const/let、箭头函数、class 相关现代语法背景[Language/[Javascript] 데이터 타입.md](Language/[Javascript] 데이터 타입.md)理解对象与基本数据类型的区别有助于加深对“对象才有原型链”的认识README.md仓库总目录可继续浏览计算机基础、数据结构、网络等其他面试主题。说明本文内容以 [Language/[Javasript] Object Prototype.md](Language/[Javasript] Object Prototype.md) 为骨架原型链查找流程、构造函数示例、__proto__与prototype的连接关系均来自该文档原型链终点为null、hasOwnProperty判定等细节为对该机制的标准行为描述可结合上文代码在浏览器控制台或 Node.js 中自行验证。赞分享教程知识库【免费下载链接】tech-interview-for-developer 신입 개발자 전공 지식 기술 면접 백과사전 项目地址https://gitcode.com/GitHub_Trending/te/tech-interview-for-developer点击查看免费下载相关推荐free-llm-api-resources项目贡献者激励机制社区建设的终极指南free llm api resources项目贡献者激励机制社区建设的终极指南 free llm api resources作为免费LLM推理资源API的精大模型人工智能模型推理服务知识库你并不懂 JS原型机制深度拆解 —— 从 [[Prototype]] 链、new 与 .prototype 到 Object.create(..) 委托设计你并不懂 JS原型机制深度拆解 —— 从 Prototype 链、 new 与 .prototype 到 Object.create .. 委托设计 本篇技术教程文档冴羽 Blog JavaScript 深入系列从原型到原型链——prototype、\_\_proto\_\_ 与 constructor 全解析冴羽 Blog JavaScript 深入系列从原型到原型链——prototype、\_\_proto\_\_ 与 constructor 全解析 本指南源自技术博客文档教程上一篇UxPlay终极指南轻松实现跨平台AirPlay镜像服务下一篇R3LIVE打造实时RGB彩色激光雷达视觉惯性紧耦合建图系统创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →