当前位置: 首页 > article >正文

原型与原型链:JavaScript 的“家族关系”大揭秘

有人说JavaScript里“万物皆对象”但对象和对象之间怎么攀亲戚今天我们就来扒一扒JS的“家族关系”——原型和原型链。看懂了它你就理解了JS面向对象的核心也能明白为什么一个数组能调用那么多方法。前言如果你第一次接触原型可能会觉得它像个黑魔法明明没在那个对象上定义方法怎么就突然能用了比如constarr[1,2,3];arr.push(4);// 哪里来的push这个push方法既不是我们手动加的也不是数组本身自带的其实数组本身也没有不信你console.log(arr)看看。它是从“祖先”那里继承来的。今天我们就来扒一扒JavaScript这个家族的族谱看看对象们是怎么“攀亲戚”的以及怎么利用这门亲戚关系写出优雅的代码。一、原型是个啥简单来说原型就是一个普通的对象它被别的对象当作“备用方案”。当你访问一个对象的属性或方法时如果这个对象自己没有JavaScript就会去它的原型上找。如果原型上也没有就去原型的原型上找直到找到或者到达尽头。这个“备用方案”的链条就是原型链。1. 每个函数都有个prototype属性在JavaScript里每个函数都有一个prototype属性箭头函数除外。这个属性指向一个对象当这个函数被用作构造函数用new调用时创建出来的实例会继承这个prototype对象上的所有属性和方法。functionPerson(name){this.namename;}Person.prototype.sayHellofunction(){console.log(你好我是${this.name});};constzhangsannewPerson(张三);zhangsan.sayHello();// 你好我是张三这里sayHello不在zhangsan自己身上但它在Person.prototype上zhangsan通过原型链找到了它。2. 每个对象都有个__proto__属性每个对象除了null都有一个__proto__属性非标准但几乎所有浏览器都实现它指向该对象的原型即构造函数的prototype。console.log(zhangsan.__proto__Person.prototype);// true这个__proto__就是连接实例和原型的“脐带”。3. 构造函数也有自己的原型构造函数本身也是对象所以它也有__proto__。它指向Function.prototype因为所有函数都是Function的实例。console.log(Person.__proto__Function.prototype);// true二、原型链从孙子到老祖宗我们来看一个完整的查找链functionAnimal(name){this.namename;}Animal.prototype.eatfunction(){console.log(${this.name}在吃东西);};functionDog(name,breed){Animal.call(this,name);this.breedbreed;}Dog.prototypeObject.create(Animal.prototype);Dog.prototype.constructorDog;Dog.prototype.barkfunction(){console.log(汪汪汪);};constwangcainewDog(旺财,土狗);wangcai.bark();// 汪汪汪 (自己原型上的)wangcai.eat();// 旺财在吃东西 (从Animal原型继承来的)wangcai.toString();// [object Object] (从Object原型来的)当调用wangcai.eat()时查找过程是这样的先看wangcai自己身上有没有eat方法 → 没有去wangcai.__proto__也就是Dog.prototype上找 → 没有去Dog.prototype.__proto__也就是Animal.prototype上找 → 找到了eat如果还没找到继续往上到Animal.prototype.__proto__也就是Object.prototype还没找到就去Object.prototype.__proto__→ 这是null链条结束返回undefined这个链条就是原型链。它像一条家族血脉从孙子到儿子到父亲到爷爷到祖宗直到追溯到null。三、原型链的终点Object.prototype所有普通对象的原型链终点都是Object.prototype。Object.prototype本身的原型是null。console.log(Object.prototype.__proto__);// nullObject.prototype上定义了一些所有对象都有的方法比如toString()、hasOwnProperty()、valueOf()等。这就是为什么你的数组、函数、正则都能用这些方法。四、如何判断属性是自己的还是继承的有时候我们需要知道一个属性是对象自己拥有的还是从原型链上继承来的。这时候可以用hasOwnProperty()functionPerson(name){this.namename;}Person.prototype.age18;constpnewPerson(张三);console.log(p.hasOwnProperty(name));// true自己的console.log(p.hasOwnProperty(age));// false继承的console.log(ageinp);// true不管自己的还是继承的只要能访问到就返回truehasOwnProperty只检查自身属性in操作符会检查整个原型链。五、修改原型的影响千万别乱动原型是共享的所以如果你修改了原型所有继承自它的实例都会受影响。functionPerson(){}constp1newPerson();constp2newPerson();Person.prototype.sayfunction(){console.log(hello);};p1.say();// hellop2.say();// hello两个实例都有了Person.prototype.sayfunction(){console.log(world);};p1.say();// world瞬间都变了这个特性有时候很有用比如给内置类型添加方法但也非常危险。尤其是在多人协作的项目里随便修改原型可能导致难以追踪的bug。注意千万不要修改内置对象的原型比如Array.prototype、Object.prototype除非你非常清楚自己在做什么。这会污染全局导致不可预测的行为。六、原型链实现继承传统方式在ES6的class出现之前JS主要靠原型链实现继承。上面的Dog继承Animal就是经典写法// 1. 定义父类构造函数functionAnimal(name){this.namename;}Animal.prototype.eatfunction(){console.log(${this.name}吃东西);};// 2. 定义子类构造函数functionDog(name,breed){Animal.call(this,name);// 继承属性this.breedbreed;}// 3. 继承方法Dog.prototypeObject.create(Animal.prototype);Dog.prototype.constructorDog;// 4. 添加子类自己的方法Dog.prototype.barkfunction(){console.log(汪汪汪);};这三步是经典组合寄生继承ES6的class语法就是它的语法糖。七、ES6 class原型的“糖衣”现在写继承用class简单多了classAnimal{constructor(name){this.namename;}eat(){console.log(${this.name}吃东西);}}classDogextendsAnimal{constructor(name,breed){super(name);// 调用父类构造函数this.breedbreed;}bark(){console.log(汪汪汪);}}看着舒服多了吧但其实它底层还是原型那一套只是帮我们省去了手动操作prototype的麻烦。八、常见坑点与最佳实践1. 不要用__proto____proto__虽然能用但不是标准虽然现代浏览器都支持而且性能也不太好。用Object.getPrototypeOf()和Object.setPrototypeOf()替代。console.log(Object.getPrototypeOf(zhangsan)Person.prototype);// true2. 小心原型链上的属性被覆盖如果子类实例定义了与原型同名的属性会“遮蔽”原型上的属性。functionPerson(){}Person.prototype.name祖先;constpnewPerson();p.name自己;console.log(p.name);// 自己原型的被遮住了deletep.name;console.log(p.name);// 祖先删除自己的又露出来了3. 用Object.create()创建对象Object.create(proto)可以创建一个新对象它的原型直接指向proto。constparent{name:父亲};constchildObject.create(parent);child.age10;console.log(child.name);// 父亲从parent继承这是创建原型关系最简单的方式。4. 尽量用class少手动操作原型现代开发中class语法足够应对绝大多数场景代码更清晰不容易出错。九、总结原型链就是JS的“家谱”每个函数都有prototype属性指向原型对象每个实例都有__proto__属性指向构造函数的prototype访问属性时先在自身找找不到就沿着__proto__往上找直到null这个链条就是原型链Object.prototype是链条的终点上面定义了所有对象都有的方法ES6的class是原型的语法糖写起来更清爽理解了原型链你就能理解JS的继承机制也能更高效地利用这个“家族关系”来复用代码。明天我们将在此基础上深入讲解继承的多种实现方式从原型链继承到ES6 class一次性帮你理清JS继承的所有姿势。如果你觉得这篇文章讲得清楚明白点个赞让更多人看到。有疑问欢迎评论区留言我们明天见

相关文章:

原型与原型链:JavaScript 的“家族关系”大揭秘

有人说JavaScript里“万物皆对象”,但对象和对象之间怎么攀亲戚?今天我们就来扒一扒JS的“家族关系”——原型和原型链。看懂了它,你就理解了JS面向对象的核心,也能明白为什么一个数组能调用那么多方法。前言 如果你第一次接触原型…...

QKFormer实战:如何在ImageNet-1K上实现85.65%准确率的尖峰Transformer模型

QKFormer实战:在ImageNet-1K上实现85.65%准确率的全流程指南 当我在实验室第一次看到QKFormer的论文时,那个85.65%的ImageNet-1K准确率数字立刻引起了我的注意——要知道,这是直接训练的SNN模型首次突破85%大关。作为一个长期在边缘设备上部署…...

NocoBase新手必看:5分钟搞定Docker安装与界面配置(附避坑指南)

NocoBase新手必看:5分钟搞定Docker安装与界面配置(附避坑指南) 1. 为什么选择NocoBase? 如果你正在寻找一款灵活、易用且功能强大的无代码开发平台,NocoBase绝对值得考虑。作为一个开源项目,它结合了Noti…...

敏捷开发实战:如何用Jira Sprint规划两周迭代任务(含模板截图)

敏捷开发实战:如何用Jira Sprint规划两周迭代任务 在快节奏的软件开发领域,两周一次的Sprint迭代已经成为许多敏捷团队的标准节奏。这种短周期、高频率的交付方式,既能保持开发节奏的紧凑性,又能确保团队对需求变化的快速响应。然…...

医学图像配准实战:用Prob-VoxelMorph实现微分同胚形变(附代码)

医学图像配准实战:用Prob-VoxelMorph实现微分同胚形变(附代码) 在医学影像分析领域,图像配准技术如同一位精准的"空间调音师",能够将不同时间、不同模态或不同个体获取的医学图像进行空间对齐。这种技术在病…...

【从零构建Berkeley Humanoid Lite:全栈开源人形机器人技术实战】第五章 Sim2Real迁移与性能优化(系统层)

目录 第五章 Sim2Real迁移与性能优化(系统层) 5.1 零样本迁移工程实践 5.1.1 策略蒸馏与量化 5.1.2 实机调试方法论 5.2 性能边界与扩展性 5.2.1 动态能力评估 5.2.2 V2版本演进路线(社区预告) 脚本1:策略蒸馏与ONNX导出优化(PyTorch) 脚本2:ROS2遥测日志与实…...

【C语言形式化验证实战指南】:20年专家亲授3大工业级案例与5步验证落地法

第一章:C语言形式化验证概述与工业落地价值C语言形式化验证是指利用数学方法对C程序的语法、语义及行为进行严格建模与逻辑推理,以证明其满足特定安全属性(如内存安全、无未定义行为、功能正确性等)。不同于传统测试或静态分析&am…...

企业上线实在 Agent,多久能收回投入成本?——深度拆解企业级AI Agent的ROI转化路径

在2026年AI Agent爆发式增长的背景下,企业上线实在Agent的投入产出比(ROI)已成为决策核心。根据当前行业基准数据,在跨境电商、营销等高频场景下,领先的Agent产品通常能在上线1个月内实现现金流转正;而在复…...

PyCharm调试Torch分布式训练的3个隐藏坑点(附2023最新解决方案)

PyCharm调试Torch分布式训练的3个隐藏坑点(附2023最新解决方案) 在深度学习领域,分布式训练已成为提升模型训练效率的标配技术。PyTorch作为当前最受欢迎的深度学习框架之一,其分布式训练功能备受开发者青睐。然而,当我…...

Pixel Dimension Fissioner免配置环境:预置中文分词器与标点规范化模块

Pixel Dimension Fissioner免配置环境:预置中文分词器与标点规范化模块 1. 产品概述 Pixel Dimension Fissioner(像素语言维度裂变器)是一款创新的文本处理工具,基于MT5-Zero-Shot-Augment核心引擎构建。它彻底改变了传统文本处…...

芯片制造企业如何解决CAD图纸粘贴到TinyMCE的矢量输出?

关于Vue内使用tinymce图片上传粘贴相关问题 最近因为工作需要,用到了富文本编辑器让用户填写反馈,上传图片等功能,经过一些对比选择了tinymce,记录下图片相关问题。 完整版封装的组件代码,放到最后。 环境 vue2.x tinymce 5.10…...

从漏洞复现到防御:手把手教你理解CVE-2021-4034(含POC分析)

深入解析CVE-2021-4034:从漏洞原理到实战防御 在Linux系统安全领域,权限提升漏洞一直是攻击者最青睐的攻击向量之一。2021年曝光的CVE-2021-4034漏洞因其影响范围广、利用难度低而备受关注。这个存在于Polkit的pkexec组件中的漏洞,允许普通用…...

金融系统如何优化Excel表格到TinyMCE5的跨平台渲染?

tinymce富文本,如何保留从word中粘贴的内容格式(vue2后台项目) 今天办公室里弥漫着一股“岁月静好”的错觉,键盘声稀疏得像老式挂钟的滴答声,同事们或对着屏幕发呆,或偷偷刷着手机,连平日里最爱…...

前端开发必备:用proj4.js搞定地图坐标转换(附完整代码示例)

前端开发必备:用proj4.js搞定地图坐标转换(附完整代码示例) 地图数据可视化是前端开发中常见的需求,但不同地图服务使用的坐标系可能各不相同。比如百度地图使用BD09坐标系,高德地图使用GCJ02坐标系,而国际…...

TinyMCE如何完美兼容Word公式粘贴并保留原始样式?

如何在富文本中插入表情,word文档,及数学公式? 前言 校外培训迎来下岗潮,教育行业的小伙伴,大家过的还好吗?不过话说回来,技术过硬,你在哪里都是最靓的仔。今天就给大家补充一点弹…...

R星服务器又抽风?从‘Social Club初始化失败’聊聊国内玩家玩外服游戏的网络生存指南

海外游戏网络连接优化指南:从Social Club故障到全局解决方案 每次打开心爱的海外游戏,却看到"Social Club初始化失败"的提示,那种烦躁感想必每个玩家都深有体会。这背后反映的不仅是某个游戏平台的临时故障,更是国内玩家…...

Nanbeige 4.1-3B一文详解:Streamlit Theming API深度定制像素UI主题方案

Nanbeige 4.1-3B一文详解:Streamlit Theming API深度定制像素UI主题方案 1. 项目背景与设计理念 Nanbeige 4.1-3B像素冒险聊天终端是一款专为对话AI设计的独特前端界面。它突破了传统聊天界面的设计范式,将现代AI交互体验与复古游戏美学完美融合。 1.…...

OpenClaw定时任务实践:GLM-4.7-Flash实现24/7自动化监控

OpenClaw定时任务实践:GLM-4.7-Flash实现24/7自动化监控 1. 为什么需要自动化监控? 去年接手一个数据采集项目时,我每天要手动检查十几个网页的数据更新情况。这种重复性工作不仅耗时,还经常因为时间差错过关键信息。直到发现Op…...

从CTF靶场到实战:手把手复现EasyCMS后台弱口令与主题导出漏洞(附POC)

从CTF靶场到实战:手把手复现EasyCMS后台弱口令与主题导出漏洞 在企业级CMS系统的安全评估中,弱口令和文件操作漏洞往往是最容易被忽视却危害极大的安全隐患。本文将基于真实渗透测试经验,详细拆解EasyCMS(及类似迅睿CMS系统&#…...

Hunyuan-MT-7B模型日志分析:ELK堆栈实战

Hunyuan-MT-7B模型日志分析:ELK堆栈实战 1. 引言 当你运行Hunyuan-MT-7B这样的翻译模型时,有没有遇到过这样的情况:模型突然变慢,却不知道问题出在哪里?或者想知道哪些翻译请求最耗时,但面对一堆杂乱的日…...

用数据说话 10个降AIGC平台测评:论文写作全流程降AI率全解析

在论文写作的全过程中,AI生成内容(AIGC)已经成为学术界和教育界关注的焦点。随着AI技术的广泛应用,许多学生和研究者发现,使用AI辅助写作虽然提升了效率,但也带来了AIGC率偏高、查重率不达标等问题。如何在…...

实测才敢推!降AI率工具 千笔·降AI率助手 VS Checkjie,开源免费首选

在AI技术快速发展的今天,越来越多的学生和研究者开始借助AI工具进行论文写作,以提高效率、优化内容结构。然而,随着学术审查标准的不断升级,AI生成内容的痕迹越来越容易被查重系统识别,导致论文AI率超标,甚…...

亲测好用 10个降AIGC工具:论文写作全流程降AI率必备神器

在学术写作日益依赖AI辅助的当下,如何有效降低论文中的AIGC率、去除明显的AI痕迹,同时保持内容的逻辑性和原创性,已成为众多学生和研究者面临的共同难题。随着各大高校和期刊对AI生成内容的审查日趋严格,传统的“复制粘贴”式写作…...

天地图JavaScript API实战:多边形面积计算与交互式绘制

1. 天地图JavaScript API基础入门 第一次接触天地图JavaScript API的开发者可能会觉得有点懵,其实它和我们常用的百度地图、高德地图API类似,都是用来在网页上展示地图和实现地理信息功能的工具链。我刚开始用的时候也踩过不少坑,后来发现只要…...

Vue3项目实战:如何用@vitejs/plugin-legacy搞定老旧浏览器兼容?

Vue3工程化实践:基于vitejs/plugin-legacy的渐进式兼容方案 当我们在现代前端工程中采用Vue3和Vite的组合时,往往会遇到一个现实矛盾:开发时享受的ES模块原生导入、闪电般的HMR,与生产环境需要支持的旧版浏览器之间的技术代沟。这…...

Qwen3.5-9B长文档理解:PDF解析+关键信息抽取+摘要生成端到端部署

Qwen3.5-9B长文档理解:PDF解析关键信息抽取摘要生成端到端部署 1. 项目概述与核心价值 Qwen3.5-9B是阿里云推出的新一代多模态大语言模型,特别针对长文档处理场景进行了优化。本文将带您从零开始部署一个完整的端到端解决方案,实现PDF文档解…...

实战指南:基于Windows Server构建企业级AAA认证体系

1. 为什么企业需要AAA认证体系 在企业IT环境中,网络设备管理一直是个头疼的问题。想象一下,公司有几十台交换机、路由器,每个设备都要单独维护账号密码,管理员得记住上百组凭证。更可怕的是,当有员工离职时&#xff0c…...

告别托管依赖:用.NET 8 Native AOT把C#代码打包成纯原生DLL,让C++项目轻松调用

告别托管依赖:用.NET 8 Native AOT把C#代码打包成纯原生DLL,让C项目轻松调用 在跨语言开发的世界里,C#和C的协作一直是个既诱人又充满挑战的话题。想象一下,你有一个用C#精心打磨的高性能算法库,或者一个成熟的业务逻辑…...

ESP32 SD卡固件更新库:DSTIKE OLED图形化OTA引导方案

1. 项目概述DstikeUpdater 是一个专为 DSTIKE 系列 ESP32 开发板设计的嵌入式固件在线更新(Over-the-Air, OTA)辅助库,其核心定位并非替代 ESP-IDF 或 Arduino-ESP32 原生 OTA 机制,而是构建一套面向终端用户的、具备图形化交互能…...

UniApp多主题切换实战:从SCSS变量到require动态引入的完整指南

UniApp多主题切换实战:从SCSS变量到require动态引入的完整指南 在移动应用开发中,多主题切换功能已经成为提升用户体验的重要特性。无论是为了适配用户偏好、实现夜间模式,还是满足品牌定制需求,灵活的主题切换机制都能显著提升产…...