5分钟内理解 .prototype 链 | 2024

ops/2024/11/14 2:06:16/

db3b43c8e932347fe5e668f3ee8b7d8b.png

在JavaScript的世界里,原型(prototype)系统是一个常被讨论但不易掌握的概念。作为JavaScript继承模型的基石,理解原型对于构建大型应用或进行对象操作至关重要。让我们一起探索这个迷人的话题,揭开原型系统的神秘面纱。

什么是原型?

在JavaScript中,每个对象都有一个内部属性[[Prototype]]。这个属性指向另一个对象,我们称之为原型。原型就像一个模板,对象从中继承属性和方法。

当我们尝试访问一个对象的属性或方法时,JavaScript首先在对象本身查找。如果没有找到,它会沿着原型链向上查找,直到找到该属性或达到原型链的顶端(null)。

我们通过一个简单的例子来理解这个过程:

const animal = {makeSound: function() {console.log("Some generic animal sound");}
};const dog = Object.create(animal);
dog.bark = function() {console.log("Woof!");
};dog.makeSound(); // 输出: "Some generic animal sound"
dog.bark();      // 输出: "Woof!"

在这个例子中,dog对象继承了animalmakeSound方法,同时拥有自己的bark方法。

创建对象与原型

我们深入了解对象创建时原型是如何链接的:

function Person(name) {this.name = name;
}Person.prototype.greet = function() {console.log(`Hello, I'm ${this.name}`);
};const alice = new Person("Alice");
alice.greet(); // 输出: "Hello, I'm Alice"

这里发生了什么?

  1. Person是一个构造函数。

  2. 当我们使用new关键字创建Person的实例时,JavaScript创建了一个新对象(alice),并将其[[Prototype]]链接到Person.prototype

  3. 当调用alice.greet()时,JavaScript首先在alice对象上查找greet方法。没有找到,所以它沿着原型链查找,在Person.prototype上找到并执行了这个方法。

原型链与继承

JavaScript通过原型实现继承。与传统的类继承不同,JavaScript对象直接从其他对象继承。这被称为"原型继承"。让我们扩展前面的例子来演示继承:

function Developer(name, language) {Person.call(this, name);this.language = language;
}Developer.prototype = Object.create(Person.prototype);
Developer.prototype.constructor = Developer;Developer.prototype.code = function() {console.log(`${this.name} is coding in ${this.language}`);
};const bob = new Developer("Bob", "JavaScript");
bob.greet(); // 输出: "Hello, I'm Bob"
bob.code();  // 输出: "Bob is coding in JavaScript"

在这个例子中:

  1. 我们使用Object.create(Person.prototype)创建了Developer.prototype,确保Developer实例继承自Person.prototype

  2. 我们重置了Developer.prototype.constructor,使其指向Developer函数。

  3. bob现在可以访问从Person.prototype继承的greet方法和定义在Developer.prototype上的code方法。

原型方法与属性遮蔽

当直接在对象上添加一个属性或方法时,它会遮蔽原型链中同名的属性或方法:

bob.greet = function() {console.log("Hi, I'm a developer!");
};bob.greet(); // 输出: "Hi, I'm a developer!"

在这个例子中,直接定义在bob上的greet方法覆盖了从Person.prototype继承的方法。

修改原型的风险

虽然可以修改内置原型如Array.prototypeObject.prototype,但这通常是不推荐的做法。这可能导致不可预知的行为和与其他代码的冲突。

结语

JavaScript的原型系统虽然初看复杂,但掌握它能让我们更深入地理解JavaScript的工作原理。尽管在使用现代JavaScript和TypeScript的项目中,我们很少直接操作原型,但理解原型对于调试和优化应用程序仍然至关重要。

通过深入理解原型,我们能够编写更高效、更灵活的JavaScript代码,为构建强大的前端应用奠定坚实基础。

最后:

CSS技巧与案例详解

vue2与vue3技巧合集

VueUse源码解读


http://www.ppmy.cn/ops/114591.html

相关文章

【.NET 8 实战--孢子记账--从单体到微服务】--特别说明

这篇文章是针对《孢子记账》实战专栏的说明文章,用以解答同学们的疑惑,后续针对专栏的疑惑我都会写在这里,各位铜同学有什么问题也可以在这篇文章下面留言。专栏的简介已经在文章《开篇》做过介绍了,不了解的请移步《开篇》。下面…

【有啥问啥】深度剖析:大模型AI时代下的推理路径创新应用方法论

深度剖析:大模型AI时代下的推理路径创新应用方法论 随着大规模预训练模型(Large Pretrained Models, LPMs)和生成式人工智能的迅速发展,AI 在多领域的推理能力大幅提升,尤其是在自然语言处理、计算机视觉和自动决策领…

《ElementUI/Plus 基础知识》el-table + sortablejs 实现 row 拖动改变顺序(Vue2/3适用)

前言 使用如下技术: ElementPlus Table 组件;插件 sortablejs ( npmjs/Github 地址); 实现 html 代码第 1 行,属性 row-key 一定要设置,否则会报错。即行数据的 Key,用来优化 t…

项目第十弹:连接管理模块与服务器模块

项目第十弹:连接管理模块与服务器模块 一、连接管理模块的设计1.连接模块的设计2. 连接管理模块的设计1.连接ID? TcpConnectionPtr!! 二、连接管理模块的实现1.连接模块的实现2.连接管理模块的实现 三、服务器模块的设计1.前言2.设计 四、服…

go webapi上传文件 部属到linux

go厉害的地方,linux服务器上无需安装任务依赖就可以运行,大赞! 一、编译 #在Goland中cmd中执行 go env -w GOARCHamd64 go env -w GOOSlinux go build main.go # 切换回来 否则无法运行 go env -w GOOSwindows go run main.go 拷贝到linux服…

ALSA ubuntu 编译

1、下载tar包:alsa-lib、alsa-utils GitHub - alsa-project/alsa-lib: The Advanced Linux Sound Architecture (ALSA) - library(核心库) GitHub - alsa-project/alsa-utils: The Advanced Linux Sound Architecture (ALSA) - utilities(工具库) 2、…

基于Java的SSM(Spring、Spring MVC、MyBatis)框架构建的远程诊断系统

基于Java的SSM(Spring、Spring MVC、MyBatis)框架构建的远程诊断系统,适用于医疗、工业设备监测等多个领域。这样的系统通常需要具备实时数据采集、数据分析、故障诊断等功能。下面是一个简化的系统设计方案,以及一些关键组件和技…

C++primer第十一章使用类(矢量随机游走实例)

操作符重载 操作符重载(operator overoading)是一种形式的 C多态。 第8章介绍了C是如何使用户能够定义多个名称相同但特征标(参数列表)不同的函数的。这被称为函数重载(function overloading)或函数多态(functional polymorphism),旨在让您能够用同名的函数来完成…