JavaScript 中的原型与继承
一、从对象说起, 一切皆对象在 JS 中, 几乎所有的东西都是对象, 或者说最终都会指向某个对象. 比如:let arr [1,2,3];console.log(typeof arr);//objectfunctionfoo() {}console.log(typeof foo);//function (但本质上也是对象)简单的对象创建:let person {name:张三,age:25,sayHi:function() {console.log(你好我是 this.name);}};person.sayHi();// 你好, 我是张三但这样有个问题——每次创建新对象都要写一遍所有属性和方法, 太麻烦了! 于是我们有了后面的构造函数. 二、构造函数对象的工厂functionPerson(name, age) {this.name name;this.age age;this.sayHi function() {console.log(你好, 我是 this.name);};}let person1 newPerson(张三,25);let person2 newPerson(李四,30);person1.sayHi();// 你好, 我是张三person2.sayHi();// 你好, 我是李四这里有几个关键点:1. 函数名通常大写开头这是约定俗成的构造函数命名方式2. 使用new关键字调用3. 函数内部使用this来指代新创建的对象当你使用new调用函数时背后发生了这些事:1. 创建一个全新的空对象2. 将这个空对象的__proto__指向构造函数的prototype属性3. 将构造函数中的this绑定到这个新对象4. 执行构造函数中的代码5. 如果构造函数没有显式返回对象则返回这个新对象三、原型登场上面的构造函数方式有个问题——每个实例都会创建自己的方法副本, 浪费内存, 这时候原型(prototype)就派上用场了!什么是原型?每个函数都有一个prototype属性, 它指向一个对象. 当使用这个函数作为构造函数创建实例时, 所有实例都会共享这个原型对象上的属性和方法.改进版的 Person:functionPerson(name, age) {this.name name;this.age age;}// 将方法放在原型上Person.prototype.sayHi function() {console.log(你好我是 this.name);};let person1 newPerson(张三,25);let person2 newPerson(李四,30);console.log(person1.sayHi person2.sayHi);// true - 现在方法是共享的了什么是原型链?当我们访问一个对象的属性时, JavaScript 会:1. 先在对象自身属性中查找2. 如果没找到, 就去对象的__proto__(即构造函数的prototype) 中查找3. 如果还没找到, 就继续往__proto__.__proto__中查找4. 直到找到Object.prototype(最顶层的原型它的__proto__是null)这就是原型链, JavaScript的继承机制.functionPerson() {}Person.prototype.species 人类;let p newPerson();console.log(p.species);//人类 - 从原型上找到的console.log(p.__proto__ Person.prototype);// trueconsole.log(Person.prototype.__proto__ Object.prototype);// trueconsole.log(Object.prototype.__proto__);// null如果对象自身有属性, 就不会去原型上找了:p.species 地球人;console.log(p.species);//地球人 - 自身的属性console.log(Person.prototype.species);//人类 - 原型上的没变delete p.species;console.log(p.species);//人类 - 删除自身属性后又从原型上找到了四、几种继承的方式1)原型链继承:functionParent() {this.parentProp 父类属性;}Parent.prototype.parentMethod function() {console.log(父类方法);};functionChild() {this.childProp 子类属性;}// 关键点: 子类的原型指向父类的实例Child.prototype newParent();let child newChild();console.log(child.childProp);// 子类属性console.log(child.parentProp);// 父类属性-通过原型链找到的child.parentMethod();// 父类方法问题:所有子类实例共享同一个父类实例的属性(如果是引用类型就麻烦了)创建子类实例时无法向父类构造函数传参2)构造函数继承:functionParent(name) {this.name name;this.colors [red,blue];}functionChild(name, age) {Parent.call(this, name);//关键点:在子类构造函数中调用父类构造函数this.age age;}let child1 newChild(张三,25);child1.colors.push(green);let child2 newChild(李四,30);console.log(child2.colors);//[red, blue]-不受child1影响优点:1. 避免了引用类型属性被所有实例共享2. 可以在子类中向父类传参缺点:方法都在构造函数中定义每次创建实例都会创建一遍方法不能继承父类原型上的方法3)组合继承:结合原型链继承和构造函数继承的优点:functionParent(name) {this.name name;this.colors [red,blue];}Parent.prototype.sayName function() {console.log(this.name);};functionChild(name, age) {Parent.call(this, name);//第二次调用Parentthis.age age;}Child.prototype newParent();//第一次调用ParentChild.prototype.constructor Child;//修复constructor指向Child.prototype.sayAge function() {console.log(this.age);};let child1 newChild(张三,25);child1.colors.push(green);child1.sayName();//张三child1.sayAge();//25let child2 newChild(李四,30);console.log(child2.colors);//[red, blue]4)寄生组合继承:functioninheritPrototype(child, parent) {let prototype Object.create(parent.prototype);// 创建父类原型的副本//Object.create 是创建以指定对象为原型的新对象的方法prototype.constructor child;// 修复constructorchild.prototype prototype;// 将副本作为子类的原型}functionParent(name) {this.name name;this.colors [red,blue];}Parent.prototype.sayName function() {console.log(this.name);};functionChild(name, age) {Parent.call(this, name);this.age age;}// 关键: 使用我们封装的inheritPrototype函数inheritPrototype(Child,Parent);Child.prototype.sayAge function() {console.log(this.age);};let child newChild(张三,25);child.sayName();// 张三child.sayAge();// 25优点:1. 只调用一次父类构造函数2. 子类原型上不会有多余的父类属性3. 原型链保持不变五、ES6的classES6 引入了class语法, 让面向对象编程更加直观:classParent {constructor(name) {this.name name;this.colors [red,blue];}sayName() {console.log(this.name);}}classChildextendsParent {constructor(name, age) {super(name);// 必须在使用this之前调用superthis.age age;}sayAge() {console.log(this.age);}}let child newChild(张三,25);child.sayName();// 张三child.sayAge();// 25class本质上仍然是基于原型的语法糖. 上面的代码大致相当于:functionParent(name) {this.name name;this.colors [red,blue];}Parent.prototype.sayName function() {console.log(this.name);};functionChild(name, age) {Parent.call(this, name);this.age age;}Child.prototype Object.create(Parent.prototype);Child.prototype.constructor Child;Child.prototype.sayAge function() {console.log(this.age);};class还提供了静态方法和属性的简洁写法:classMyClass {staticstaticMethod() {console.log(我是静态方法);}static staticProperty 我是静态属性;}MyClass.staticMethod();//我是静态方法console.log(MyClass.staticProperty);//我是静态属性六、其他相关内容instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上.functionmyInstanceof(instance, constructor) {let proto Object.getPrototypeOf(instance);while (proto) {if (proto constructor.prototype) {returntrue;}proto Object.getPrototypeOf(proto);}returnfalse;}console.log([]instanceofArray);// trueconsole.log(myInstanceof([],Array));// true原型可以被修改, 这可能导致安全问题:// 不要这样做Object.prototype.hack function() {console.log(被黑了);};let obj {};obj.hack();// 被黑了

相关新闻

大白话总结:全域统一场论(四大力统一终极方程)

大白话总结:全域统一场论(四大力统一终极方程)

大白话总结:全域统一场论(四大力统一终极方程) 作者:AI科技星 一、最核心的一句话(看懂就全懂) 宇宙没有四种力,只有时空的两种变形:弯曲(引力)、扭转&#x…

2026/7/23 6:25:12 阅读更多 →
电商项目微服务拆分实战

电商项目微服务拆分实战

前言:任何软件架构的迭代,都是为了适配业务规模的增长。电商平台作为互联网最典型的高并发、高迭代、多业务场景系统,架构演进路径极具代表性:从初创时期的单体架构,逐步迭代为分布式微服务架构。一、架构演进背景&…

2026/7/23 8:24:28 阅读更多 →
Unity 物理系统进阶:重力设置与自定义重力效果

Unity 物理系统进阶:重力设置与自定义重力效果

Unity 物理系统进阶:重力设置与自定义重力效果📚 本章学习目标:深入理解重力设置与自定义重力效果的核心概念与实践方法,掌握关键技术要点,了解实际应用场景与最佳实践。本文属于《Unity工程师成长之路教程》Unity 物理…

2026/7/23 6:49:58 阅读更多 →

最新新闻

HarmonyOS API 23 ArkTS 实战:实现一个轻量级纪念日倒计时应用

HarmonyOS API 23 ArkTS 实战:实现一个轻量级纪念日倒计时应用

开发环境:HarmonyOS NEXT 6.1.0(API 23)、Stage应用开发模型、DevEco Studio 6.1 Beta、Hvigor增量编译构建体系核心技术栈:ArkTS强类型静态编程、声明式UI架构、单向响应式数据流、高精度时间差值计算、系统定时器调度、TextTime…

2026/7/24 3:27:26 阅读更多 →
Windows错误0x80004005诊断与修复全指南

Windows错误0x80004005诊断与修复全指南

1. 错误代码0x80004005的本质解析这个看似简单的错误代码背后隐藏着复杂的系统运行机制。作为Windows系统中常见的通用错误代码,0x80004005实际上是一个十六进制的HRESULT值,转换为十进制就是-2147467259。这种编码方式包含了错误来源、严重程度等元信息…

2026/7/24 3:27:26 阅读更多 →
不会整理链接里的目标视频?试试链接提取视频的实用方法

不会整理链接里的目标视频?试试链接提取视频的实用方法

从网页、分享链接中提取目标视频可使用正规在线解析工具完成操作,适合需要提取公开分享链接中目标视频做二次创作的自媒体从业者。关键依据是当前多数公开内容链接支持合规提取自用内容,前提是仅用于个人学习、原创二次创作,不适合提取有版权…

2026/7/24 3:27:26 阅读更多 →
MacOS彻底卸载openclaw及残留文件指南

MacOS彻底卸载openclaw及残留文件指南

1. 项目概述"彻底删除openclaw指南 Mac OS版"这个标题指向了一个非常具体的需求:在macOS系统上完全移除openclaw软件及其相关组件。作为一款可能用于网络抓取或自动化操作的软件,openclaw在卸载后往往会留下各种残留文件,这正是本指…

2026/7/24 3:27:26 阅读更多 →
AI赋能学术专著写作:工具、方法与质量保障

AI赋能学术专著写作:工具、方法与质量保障

1. 项目概述作为一名在学术出版领域深耕多年的从业者,我见证了AI技术如何彻底改变专著写作的范式。这本《AI专著撰写宝典》的诞生,源于我观察到的一个普遍现象:即使是经验丰富的研究者,在面对动辄数十万字的专著写作时&#xff0c…

2026/7/24 3:27:26 阅读更多 →
虚拟试穿系统架构与算法优化实战

虚拟试穿系统架构与算法优化实战

1. 项目背景与核心价值虚拟试穿技术正在彻底改变传统电商的购物体验。去年双十一期间,某头部电商平台数据显示,采用AR试穿功能的商品转化率比普通商品高出47%,退货率降低32%。这组数据直观展现了这项技术的商业价值。我参与过三个虚拟试穿系统…

2026/7/24 3:26:26 阅读更多 →

日新闻

用Highcharts 创建可拖拽三维散点立方体3D图表

用Highcharts 创建可拖拽三维散点立方体3D图表

该案例基于Highcharts scatter3d 三维散点图实现空间立方体散点可视化,核心特色:三维 X/Y/Z 三轴空间,所有散点分布在 0~10 立方体空间内;散点使用径向渐变实现立体 3D 圆球质感;支持鼠标 / 触屏拖拽画布,…

2026/7/24 0:00:29 阅读更多 →
AppCertDlls:进程创建路径上的 DLL 入口

AppCertDlls:进程创建路径上的 DLL 入口

AppCertDlls:进程创建路径上的 DLL 入口 AppCertDlls 位于 HKLM\System\CurrentControlSet\Control\Session Manager\AppCertDlls。本文的程序功能是只读列出这个键在 64 位和 32 位注册表视图中的全部值,并显示每条值的来源、名称、类型和可安全显示的数…

2026/7/24 0:00:29 阅读更多 →
我的编程之路:第一篇博客

我的编程之路:第一篇博客

大家好,我是一名编程初学者,同时这也是我编程学习之路上的第一篇博客。在这里,我想要向大家介绍我的一些想法和规划。a.自我介绍我是一个刚刚接触编程的新手,目前在学习c语言,我对编程世界充满了强烈的好奇。当然&…

2026/7/24 0:00:29 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/22 8:58:19 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/24 1:23:39 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/23 17:49:47 阅读更多 →

月新闻