文章目录

  • JavaScript原型与原型链:对象的"家族传承"系统 👨👩👧👦
    • 引言:为什么需要原型?
    • 原型系统三大核心概念
      • 概念关系图
      • 核心概念表
    • 一、原型基础:对象如何"继承"属性
      • 1. 创建对象与原型关系
      • 2. 原型链查找机制
    • 二、深入原型链:多级继承
      • 1. 原型链示意图
      • 2. 实现继承的完整例子
      • 3. 原型链关系验证方法
    • 三、原型系统的六大核心机制
      • 1. `new` 操作符的工作流程
      • 2. 构造函数、原型与实例的关系
      • 3. 原型链的终点
      • 4. 属性屏蔽规则
      • 5. 原型污染与防范
      • 6. 现代替代方案:Class语法
    • 四、原型系统的实际应用
      • 1. 方法共享(节省内存)
      • 2. 猴子补丁(Monkey Patching)
      • 3. 对象组合与混入(Mixin)
    • 五、常见误区与最佳实践
      • 1. 常见错误
      • 2. 最佳实践
      • 3. 原型调试技巧
    • 总结:原型系统的设计哲学

在这里插入图片描述

JavaScript原型与原型链:对象的"家族传承"系统 👨👩👧👦

引言:为什么需要原型?

想象JavaScript世界是一个巨大的家族,每个对象都是这个家族的成员:

  • 问题:如果每个家庭成员都从头开始学习所有知识(每个对象都独立拥有全部属性和方法),效率极低
  • 解决方案:家族智慧通过"血脉"传承(原型继承)
  • 结果:后代可以自动获得祖先的知识和能力,无需重复学习

这就是JavaScript原型系统的设计初衷——高效共享属性和方法

原型系统三大核心概念

概念关系图

构造函数 (Constructor) → 实例 (Instance)↓
.prototype (原型对象)↑
.__proto__ (原型链接)

彻底搞懂JavaScript原型和原型链-CSDN博客

核心概念表

概念说明类比家庭关系
构造函数用于创建对象的函数父母
实例通过构造函数创建的对象孩子
原型对象包含共享属性和方法的对象家族共享的知识库
__proto__实例指向原型对象的链接血脉传承
prototype构造函数的原型属性父母准备给孩子的知识库

一、原型基础:对象如何"继承"属性

1. 创建对象与原型关系

// 1. 创建一个构造函数(父母)
function Person(name) {this.name = name;
}// 2. 在原型上添加方法(家族共享知识)
Person.prototype.greet = function() {console.log(`Hello, my name is ${this.name}`);
};// 3. 创建实例(孩子)
const alice = new Person('Alice');
const bob = new Person('Bob');// 4. 调用方法
alice.greet(); // Hello, my name is Alice
bob.greet();   // Hello, my name is Bob// 检查原型关系
console.log(alice.__proto__ === Person.prototype); // true
console.log(Object.getPrototypeOf(alice) === Person.prototype); // true (标准方法)

2. 原型链查找机制

当访问对象属性时,JavaScript会:

1. 检查对象自身属性 → 有则返回
2. 没有则检查__proto__指向的原型对象 → 有则返回
3. 重复步骤2直到找到或到达null
// 继续上面的例子// 1. 直接访问实例属性
console.log(alice.name); // "Alice" (自身属性)// 2. 访问原型方法
alice.greet(); // 方法在原型上找到// 3. 添加自身方法会覆盖原型方法
alice.greet = function() {console.log(`Special greeting from ${this.name}`);
};
alice.greet(); // Special greeting from Alice (优先使用自身方法)
bob.greet();   // Hello, my name is Bob (仍然使用原型方法)// 4. 检查属性存在性
console.log('name' in alice); // true (自身属性)
console.log('greet' in alice); // true (原型链上存在)
console.log(alice.hasOwnProperty('name')); // true
console.log(alice.hasOwnProperty('greet')); // false (原型上的)

二、深入原型链:多级继承

1. 原型链示意图

实例 alice↓ __proto__
Person.prototype↓ __proto__
Object.prototype↓ __proto__
null

2. 实现继承的完整例子

// 父类(基类)
function Animal(name) {this.name = name;
}// 父类原型方法
Animal.prototype.eat = function() {console.log(`${this.name} is eating.`);
};// 子类(派生类)
function Dog(name, breed) {Animal.call(this, name); // 调用父类构造函数this.breed = breed;
}// 设置原型链继承
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog; // 修复constructor指向// 子类原型方法
Dog.prototype.bark = function() {console.log(`${this.name} (${this.breed}) says: Woof!`);
};// 创建实例
const myDog = new Dog('Rex', 'Labrador');// 方法调用
myDog.eat();  // Rex is eating. (继承自Animal)
myDog.bark(); // Rex (Labrador) says: Woof! (自身方法)// 检查原型链
console.log(myDog.__proto__ === Dog.prototype); // true
console.log(myDog.__proto__.__proto__ === Animal.prototype); // true
console.log(myDog instanceof Dog); // true
console.log(myDog instanceof Animal); // true

3. 原型链关系验证方法

方法用途示例
instanceof检查对象是否是某构造函数的实例obj instanceof Constructor
isPrototypeOf检查对象是否在另一个对象的原型链上Parent.prototype.isPrototypeOf(child)
Object.getPrototypeOf获取对象的原型Object.getPrototypeOf(obj)
hasOwnProperty检查属性是否是对象自身属性obj.hasOwnProperty('prop')

三、原型系统的六大核心机制

1. new 操作符的工作流程

当执行 new Constructor() 时:

1. 创建一个空对象 {} 
2. 设置该对象的__proto__指向Constructor.prototype
3. 将构造函数内的this绑定到这个新对象
4. 执行构造函数代码(初始化属性)
5. 如果构造函数没有返回对象,则返回这个新对象

2. 构造函数、原型与实例的关系

function Person(name) {this.name = name;
}const alice = new Person('Alice');// 关系验证
console.log(Person.prototype.constructor === Person); // true
console.log(alice.__proto__ === Person.prototype); // true
console.log(alice.constructor === Person); // true (通过原型链查找)

3. 原型链的终点

所有原型链最终都会指向 Object.prototype,而 Object.prototype.__proto__null

console.log(Object.prototype.__proto__); // null// 完整的原型链示例
function Foo() {}
const foo = new Foo();// 原型链:
// foo → Foo.prototype → Object.prototype → null

4. 属性屏蔽规则

当对象和原型有同名属性时:

  • 对象自身属性优先("屏蔽"原型属性)
  • 设置属性只会影响对象自身,不会修改原型
function Person() {}
Person.prototype.name = 'Prototype Name';const p1 = new Person();
const p2 = new Person();p1.name = 'Instance Name';console.log(p1.name); // 'Instance Name' (自身属性)
console.log(p2.name); // 'Prototype Name' (原型属性)

5. 原型污染与防范

原型污染:修改原型会影响所有实例

// 危险操作 - 修改内置原型
Array.prototype.push = function() {console.log('Array push modified!');
};
[].push(); // 所有数组实例受影响// 防范方法
Object.freeze(Array.prototype); // 冻结原型防止修改

6. 现代替代方案:Class语法

ES6的class本质是原型继承的语法糖

class Person {constructor(name) {this.name = name;}greet() {console.log(`Hello, ${this.name}`);}
}// 等同于
function Person(name) {this.name = name;
}
Person.prototype.greet = function() {console.log(`Hello, ${this.name}`);
};

四、原型系统的实际应用

1. 方法共享(节省内存)

// 所有实例共享同一个方法,而不是每个实例创建副本
function Car(model) {this.model = model;
}Car.prototype.drive = function() {console.log(`${this.model} is driving`);
};const car1 = new Car('Tesla');
const car2 = new Car('BMW');console.log(car1.drive === car2.drive); // true (同一个方法)

2. 猴子补丁(Monkey Patching)

// 在运行时修改或扩展已有类型
const arr = [1, 2, 3];// 添加自定义方法(谨慎使用)
Array.prototype.last = function() {return this[this.length - 1];
};console.log(arr.last()); // 3

3. 对象组合与混入(Mixin)

// 通过原型实现混入模式
const canEat = {eat: function() {console.log(`${this.name} is eating`);}
};const canSleep = {sleep: function() {console.log(`${this.name} is sleeping`);}
};function Person(name) {this.name = name;
}// 混入多个行为
Object.assign(Person.prototype, canEat, canSleep);const p = new Person('Alice');
p.eat();   // Alice is eating
p.sleep(); // Alice is sleeping

五、常见误区与最佳实践

1. 常见错误

// 错误1:忘记使用new操作符
function Person(name) {this.name = name;
}
const p = Person('Alice'); // this指向全局对象!
console.log(name); // 'Alice' (污染全局)// 错误2:直接重写prototype对象
function Foo() {}
Foo.prototype = { // 会丢失constructormethod1: function() {}
};
// 应该保持constructor
Foo.prototype = {constructor: Foo,method1: function() {}
};// 错误3:在继承中破坏原型链
function Parent() {}
function Child() {}
Child.prototype = Parent.prototype; // 错误 - 修改Child会影响Parent
// 正确做法
Child.prototype = Object.create(Parent.prototype);

2. 最佳实践

  1. 方法放在原型上:共享方法节省内存
  2. 属性放在构造函数中:实例特有属性
  3. 使用Object.create设置继承:保持原型链完整
  4. 不要修改内置原型:避免不可预测行为
  5. 考虑使用class语法:更清晰的继承语法

3. 原型调试技巧

function Person(name) {this.name = name;
}
Person.prototype.greet = function() {console.log(`Hello, ${this.name}`);
};const p = new Person('Alice');// 1. 查看对象自身属性
console.log(Object.keys(p)); // ['name']// 2. 查看所有可枚举属性(包括原型链)
for (let key in p) {console.log(key); // 'name', 'greet'
}// 3. 检查属性来源
console.log(p.__proto__.hasOwnProperty('greet')); // true

总结:原型系统的设计哲学

JavaScript的原型系统是其面向对象编程的核心,理解它能让你:

  1. 真正掌握JavaScript对象模型:不再只是"使用"对象,而是"理解"对象
  2. 编写更高效的代码:合理利用原型共享,减少内存消耗
  3. 实现复杂的继承结构:构建可维护的大型应用
  4. 深入理解现代框架:React/Vue等框架底层都涉及原型概念
  5. 应对高级面试问题:原型相关问题是JavaScript面试的必考点

记住这个简单公式:

JavaScript对象 = 自身属性 + 原型链查找

原型系统就像JavaScript对象的DNA,它决定了对象如何"出生"、如何"成长"、以及如何"传承"特性。掌握了它,你就掌握了JavaScript面向对象编程的精髓。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/95331.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/95331.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/95331.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据库语法差异对比

特性MySQLMSSQLOraclepostgresql单行注释--、#&#xff08;少&#xff09;------多行注释/* *//* *//* *//* */字符串连接<code>CONCAT(str1,str2)</code>、<code>CONCAT_WS(separator, str1, str2)</code>、CONCAT&#xff08;str1,str2&#xff09;(…

GIS大学课程表都长啥样?几个地信专业的大学一周课程表

前几天&#xff0c;有个准大一的同学问&#xff1a;地信大学课程安排都是啥样的&#xff1f;简单的地理学、遥感学课程之类的对准大一的同学们来说太抽象了&#xff0c;有没有更具体一点的&#xff1f;他在新生群里问本校的学长&#xff0c;得到的课表不是这样的&#xff1a;就…

leetcode 3027. 人员站位的方案数 II 中等

给你一个 n x 2 的二维数组 points &#xff0c;它表示二维平面上的一些点坐标&#xff0c;其中 points[i] [xi, yi] 。 我们定义 x 轴的正方向为 右 &#xff08;x 轴递增的方向&#xff09;&#xff0c;x 轴的负方向为 左 &#xff08;x 轴递减的方向&#xff09;。类似的…

oracle 从一张表更新到另外一张表的方法(MERGE)

之前更新表格经常用 update aaa set (aaa.q,aaa.w) (select bbb.q,bbb.w from bbb where bbb.eaaa.e)的方法 后面学习了一个新的方法&#xff0c;MERGE法&#xff0c;这种写法更适合&#xff0c;因为对于空的值可以自定义定义其值&#xff0c;这样写存储过程的时候就不需要频繁…

Huggingface终于没忍住,OpenCSG坚持开源开放

在全球人工智能竞争进入白热化的当下&#xff0c;开源与闭源之路的选择正在成为决定未来格局的关键。当全球最大的AI开源平台Hugging Face终于承认"开源是赢得AI竞赛的关键"&#xff0c;并呼吁美国重新重视开源赛道时&#xff0c;OpenCSG&#xff08;开放传神&#x…

计算机网络模型总概述

//网络通讯 --- 不同主机之间的通信(进程间通信) 一、概述 目前使用的计算机网络模型主要分为两个&#xff1a;OSI七层模型和TCP/IP模型 相比OSI七层模型 &#xff0c;TCP/IP模型更简洁&#xff0c;更实用&#xff0c;因此目前所使用的基本都是TCP/IP模型&#xff0c;已成为…

HTTPS -> HTTP 引起的 307 状态码与HSTS

1.应用场景 主要用于了解HSTS, 以及如何合理设置, 如正式服和测试服, 开发环境; 摘要&#xff1a;当HTTPS网站返回307状态码临时重定向到HTTP时&#xff0c;会带来安全风险&#xff08;如中间人攻击和混合内容问题&#xff09;。 HSTS机制通过强制HTTPS通信可解决此问题&#…

PortSwigger靶场之DOM XSS in document.write sink using source location.search通关秘籍

一、靶场描述这个靶场在搜索查询的跟踪功能中&#xff0c;包含一个基于DOM的跨站脚本&#xff08;DOM-based XSS&#xff09;漏洞。该漏洞的产生是因为网站使用了一个名为 document.write 的 JavaScript 函数&#xff0c;这个函数会把数据直接写入到页面中。而写入的数据来源于…

深度学习篇---Pytorch常用优化器

优化器介绍&#xff1a;在 PyTorch 中&#xff0c;优化器&#xff08;Optimizer&#xff09;的作用是根据模型参数的梯度来更新参数&#xff0c;以最小化损失函数。下面用通俗易懂的方式介绍几种常用的优化器&#xff1a;1. SGD&#xff08;随机梯度下降&#xff09;最基础的优…

0903 C++类的运算符重载、静态成员与继承

Part 1.梳理思维导图一.运算符重载1.运算符重载的作用使原本只能对基本数据类型生效的运算符&#xff0c;在重载后&#xff0c;满足可以对构造类型数据生效。2.关系运算符重载a.关系运算符种类> > < < !b.分析参数表达式…

Cloudflare安全规则实用指南:从路径拦截到IP限制的10个经典范例

前言&#xff1a;在Cloudflare的安全防护体系中&#xff0c;自定义规则是抵御特定威胁的“精准武器”。除了基础的路径拦截&#xff0c;日常运维中还有许多高频场景需要针对性配置。本文将通过10个实用范例&#xff0c;带你掌握Cloudflare规则的灵活用法&#xff0c;覆盖路径防…

数据结构(时空复杂度)

目录 一、算法复杂度 二、时间复杂度 1.不同时间度代码举例 三、空间复杂度 一、算法复杂度 算法复杂度&#xff08;评估算法优劣一个重要指标&#xff09;分为时间复杂度和空间复杂度。 时间复杂度是指执行算法所需要的计算工作量&#xff0c;而空间复杂度是指执行这个…

ESXI8多网卡链路聚合

1. 背景 测试服务器只有千兆网卡&#xff0c;增加上行带宽&#xff0c;使用两块网卡做链路聚合。 2. 环境 VM ESXI 8.0 华为交换机 S5735S 3. 交换机配置 负载均衡方式采用了src-dst-ipTrunk模式采用了手工负载分担&#xff08;测试了静态LACP&#xff0c;未成功&#xff09;4.…

从“人工驱动”到“AI协同”:良策金宝AI如何助力设计院数智化跃迁?

在“双碳”目标驱动下&#xff0c;电力工程项目的数量与复杂度持续攀升。设计院面临“项目多、周期短、人力紧”的三重压力&#xff0c;传统的“人工驱动”模式已难以为继。良策金宝AI&#xff0c;正是这场变革的核心引擎。它以AI驱动数智化服务&#xff0c;为工程设计企业提供…

vue3 vite 自适应方案

两种方案&#xff1a; 1 使用 postcss-pxtorem插件 npm install postcss-pxtorem autoprefixer --save-dev # 或 yarn add postcss-pxtorem autoprefixer -D 2、postcss-px-to-viewport npm install postcss-px-to-viewport --save-dev 或 yarn add postcss-px-to-viewport -D …

华为研发投资与管理实践(IPD)读书笔记

在全球科技产业竞争日趋激烈的背景下&#xff0c;企业研发管理早已告别 “依赖个体经验、靠运气突破” 的粗放时代&#xff0c;如何将研发创新从 “偶然成功” 转化为 “可复制、可持续的必然成果”&#xff0c;成为所有追求长期竞争力的企业必须破解的命题。华为&#xff0c;作…

【LeetCode_283】移动零

刷爆LeetCode系列LeetCode第283题&#xff1a;github地址前言题目描述题目与思路分析代码实现算法代码优化LeetCode第283题&#xff1a; github地址 有梦想的电信狗 前言 本文用C实现 LeetCode 第283题 题目描述 题目链接&#xff1a;https://leetcode.cn/problems/move-z…

一文弄懂C/C++不定参数底层原理

目录 一、C语言的可变参数&#xff1a;基于栈帧的手动读取 &#xff08;1&#xff09;C函数调用的栈帧结构 &#xff08;2&#xff09;C 可变参数的 4 个核心宏&#xff1a;如何 “手动读栈” &#xff08;3&#xff09;实战代码&#xff1a;用 C 可变参数实现求和函数 &a…

【Android】【设计模式】抽象工厂模式改造弹窗组件必知必会

写一个 Android 版本的抽象工厂弹窗 Manager 管理器&#xff0c;使用 DialogFragment 实现&#xff0c;这样能更贴近真实的开发场景。结构设计 抽象产品&#xff1a;BaseDialogFragment&#xff08;继承 DialogFragment&#xff09;具体产品&#xff1a;LoginDialogFragment, …

Win64OpenSSL-3_5_2.exe【安装步骤】

官网下载 注意&#xff1a;科学上网&#xff0c;可以加速下载速度&#xff01; Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions 下载后得到&#xff1a;Win64OpenSSL-3_5_2.exe 双击安装 修改安装路径&#xff1a; 默认就选择第一个。 重要提醒​…