JavaScript中的原型和原型链

给大家推荐一个实用面试题库

1、前端面试题库 (面试必备)            推荐:★★★★★

地址:web前端面试题库

原型和原型链是JavaScript中一个重要且常常被误解的概念。它们在理解对象、继承和属性查找时扮演着关键的角色。

1. 原型:JavaScript对象的基础

在JavaScript中,几乎所有的对象都是通过构造函数(constructor)创建的。每个构造函数都有一个特殊的属性称为原型(prototype),它是一个对象,包含了构造函数的属性和方法。当我们创建一个对象时,它会继承构造函数的原型上的属性和方法。

1.1 构造函数和原型的关系

让我们通过一个示例来理解构造函数和原型之间的关系:

function Person(name, age) {
  this.name = name;
  this.age = age;
}

// 创建一个 Person 对象
const person1 = new Person('Alice', 25);

// 创建另一个 Person 对象
const person2 = new Person('Bob', 30);

console.log(person1.name); // 输出 'Alice'
console.log(person2.age);  // 输出 30

在上面的示例中,我们定义了一个 Person 构造函数,它有两个属性 name 和 age。然后,我们使用 new 关键字创建了两个 Person 对象 person1 和 person2。这两个对象继承了 Person 构造函数的属性。

1.2 对象的原型

每个JavaScript对象都有一个指向其原型的隐藏属性 [[Prototype]](通常通过 __proto__ 访问)。这个原型对象是一个普通对象,它包含了对象的方法和属性。

让我们看一下 person1 对象的原型:

console.log(person1.__proto__); // 输出 Person {}

image.png

person1 的原型是一个空的对象,它实际上就是 Person 构造函数的原型。这意味着 person1 可以访问 Person 构造函数原型上的属性和方法。它们之间的关系可以用下图表示:

image.png

 需要注意:constructor 是原型的一个属性。

1.3 属性查找过程

当我们访问一个对象的属性时,JavaScript 引擎会首先查找对象本身是否包含这个属性。如果对象没有这个属性,它会继续查找对象的原型,以及原型链上的其他原型,直到找到属性或查找到达原型链的末端。

让我们来看一个属性查找的例子:

console.log(person1.name); // 输出 'Alice'
console.log(person1.toString()); // 输出 '[object Object]'

在上面的示例中,当我们访问 person1 的 name 属性时,它首先查找 person1 对象本身,找到了属性 name 并输出 'Alice'。当我们调用 toString() 方法时,它查找 person1 对象本身没有这个方法,然后继续查找 Person 构造函数的原型,最终找到了 Object 构造函数的原型上的 toString() 方法。

2. 原型链:连接原型的链条

原型链是由一系列对象链接在一起的链条,用于实现属性和方法的继承。每个对象都有一个原型,这个原型又有自己的原型,以此类推,形成了原型链。原型链的终点是一个对象,它的原型为 null

2.1 原型链的构建

让我们通过一个例子来构建原型链:

function Animal(name) {
  this.name = name;
}

// Animal 的原型
Animal.prototype.eat = function() {
  console.log(`${this.name} is eating.`);
};

function Dog(name, breed) {
  // 调用 Animal 构造函数
  Animal.call(this, name);
  this.breed = breed;
}

// 建立原型链,使 Dog 继承 Animal
Dog.prototype = Object.create(Animal.prototype);

// Dog 的原型
Dog.prototype.bark = function() {
  console.log(`${this.name} is barking.`);
};

const myDog = new Dog('Buddy', 'Golden Retriever');

在上面的示例中,我们定义了一个 Animal 构造函数和一个 Dog 构造函数。然后,我们通过 Object.create() 来建立原型链,使 Dog 继承了 Animal。最后,我们创建了一个 myDog 对象。

2.2 属性和方法的继承

现在,myDog 对象继承了 Dog 构造函数和 Animal 构造函数的属性和方法。这意味着它可以访问 Dog 构造函数原型上的方法 bark,以及 Animal 构造函数原型上的方法 eat

myDog.bark(); // 输出 'Buddy is barking.'
myDog.eat();  // 输出 'Buddy is eating.'

在上面的示例中,myDog 对象成功地继承了原型链上的属性和方法。

2.3 修改原型链上的方法

你还可以在继承的基础上修改原型链上的方法,以满足子类型的需求。

// 修改 Dog 原型上的方法
Dog.prototype.bark = function() {
  console.log(`${this.name} is barking loudly.`);
};

myDog.bark(); // 输出 'Buddy is barking loudly.'

在上面的示例中,我们修改了 Dog 构造函数原型上的 bark 方法,使其输出不同的消息。

2.4 原型链的终点

原型链的终点是一个对象,它的原型为 null。这个对象是所有对象原型链的顶层,没有任何属性或方法。

console.log(Object.getPrototypeOf(Object.prototype)); // 输出 null

在上面的示例中,我们使用 Object.getPrototypeOf() 方法来获取 Object.prototype 的原型,发现它的原型是 null

3. JavaScript中的内置原型链

在JavaScript中,每个对象都继承自 Object 构造函数的原型。这意味着所有对象都具有一些通用的属性和方法,例如 toString()valueOf() 等。

3.1 Object.prototype

所有对象的原型链的顶端都是 Object.prototype,它包含了一些通用的方法,例如 toString() 和 valueOf()

const obj = {};
console.log(obj.toString()); // 输出 '[object Object]'

在上面的示例中,我们使用 obj 对象调用了 toString() 方法,这个方法实际上是从 Object.prototype 继承而来的。

3.2 Array.prototype

数组对象继承自 Array.prototype,这个原型包含了许多用于操作数组的方法,如 push()pop()forEach() 等。

const numbers = [1, 2, 3, 4, 5];
console.log(numbers.length); // 输出 5
numbers.push(6);
console.log(numbers); // 输出 [1, 2, 3, 4, 5, 6]

在上面的示例中,我们使用了 Array.prototype 上的方法来操作数组 numbers

3.3 Function.prototype

所有函数对象继承自 Function.prototype,这个原型包含了一些用于函数的方法,如 call() 和 apply()

function greet(name) {
  console.log(`Hello, ${name}!`);
}

greet.call(null, 'Alice'); // 输出 'Hello, Alice!'

在上面的示例中,我们使用了 Function.prototype 上的 call() 方法来调用函数 greet

4. 实际应用:原型和原型链的使用

原型和原型链在JavaScript中的实际应用非常广泛,它们是面向对象编程的基础,并且可以用于实现继承和共享方法。以下是一些实际应用的示例:

4.1 继承

通过构造函数和原型链,你可以实现对象之间的继承关系,创建子类型并继承父类型的属性和方法。

function Shape() {
  this.color = 'red';
}

Shape.prototype.getArea = function() {
  return 0;
};

function Circle(radius) {
  this.radius = radius;
}

// Circle 继承 Shape
Circle.prototype = Object.create(Shape.prototype);

// 添加 Circle 自己的方法
Circle.prototype.getArea = function() {
  return Math.PI * Math.pow(this.radius, 2);
};

const circle = new Circle(5);
console.log(circle.color);    // 输出 'red',继承自 Shape
console.log(circle.getArea()); // 输出 78.53981633974483,来自 Circle

在上面的示例中,我们创建了一个 Shape 构造函数,它有一个 color 属性和一个 getArea() 方法。然后,我们创建了一个 Circle 构造函数,通过原型链实现了对 Shape 的继承,并添加了自己的 getArea() 方法。

4.2 对象的共享方法

通过将方法添加到原型上,可以实现多个对象之间共享方法,节省内存并提高性能。

function Car(make, model) {
  this.make = make;
  this.model = model;
}

// 将方法添加到 Car 构造函数的原型上
Car.prototype.start = function() {
  console.log(`Starting ${this.make} ${this.model}`);
};

const car1 = new Car('Toyota', 'Camry');
const car2 = new Car('Honda', 'Accord');

car1.start(); // 输出 'Starting Toyota Camry'
car2.start(); // 输出 'Starting Honda Accord'

在上面的示例中,我们将 start() 方法添加到 Car 构造函数的原型上,这意味着所有的 Car 对象都可以共享这个方法。

4.3 使用对象字面量创建对象

对象字面量是一种方便快捷的方式来创建对象,但它们实际上是通过原型链继承自 Object 构造函数的。

const person = {
  name: 'John',
  age: 30,
};

console.log(person.toString()); // 输出 '[object Object]'

在上面的示例中,person 对象是通过对象字面量创建的,它实际上继承了 Object.prototype 上的方法,包括 toString()

5. 总结

原型和原型链是JavaScript中非常重要的概念,它们用于实现对象的继承和方法的共享。了解原型和原型链的工作原理对于理解JavaScript中的对象和继承非常关键。

总结一下:

  • 原型是构造函数的属性,它包含了构造函数的方法和属性,被新创建的对象继承。
  • 原型链是一系列对象链接在一起的链条,用于实现属性和方法的继承。
  • 所有对象都有一个原型,它可以通过 __proto__ 或 Object.getPrototypeOf() 来访问。
  • 原型链的顶端是 Object.prototype,它包含了一些通用的方法。
  • 通过构造函数和原型链,可以实现对象之间的继承和方法的共享。

 给大家推荐一个实用面试题库

1、前端面试题库 (面试必备)            推荐:★★★★★

地址:web前端面试题库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/144821.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

clickhouse的安装和配置

使用虚拟机测试, 系统为ubuntu 22.04 一 安装 sudo apt-get install -y apt-transport-https ca-certificates dirmngr sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 8919F6BD2B48D754echo "deb https://packages.clickhouse.com/deb stable ma…

μC/OS-II---内存管理2(os_core.c)

流程---内存管理扩展 初始化μC/OS-II创建用户起始任务开始多任务调度统计Task创建用户应用程序任务 初始化μC/OS-II void OSInit (void) {OSInitHookBegin(); /* Call port specific initialization code */OS_InitMisc(); …

μC/OS-II---Task管理2(os_task.c)

目录 改变Task优先级Task挂起Task恢复Task信息获取Task调度器上锁(os_core.c)Task调度器开锁(os_core.c) 改变Task优先级 #if OS_TASK_CHANGE_PRIO_EN > 0u INT8U OSTaskChangePrio (INT8U oldprio,INT8U newprio) { #if (…

2023/11/14JAVA学习

主子线程每次执行顺序可能都不一样

什么猫罐头好吃?猫咪嘎嘎炫的5款猫主食罐头推荐!

想必铲屎官都知道给猫咪长期吃主食罐头的好处了吧!主食罐头不仅营养丰富,还能让猫咪顺便补充水分。有时候猫咪食欲不佳,一罐猫主食罐头就能让它们胃口大开呢~ 作为家里有3只猫的铲屎官来说,养猫的这几年可以说血泪史了&#xff0…

Java版企业电子招标采购系统源码—企业战略布局下的采购寻源

项目说明 随着公司的快速发展,企业人员和经营规模不断壮大,公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境,最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范,以及审…

HTML5响应式网页设计(考试题:旅游项目)

效果图 .html代码 <!DOCTYPE html> <html><head><meta name"viewport"content"widthdevice-width,initial-scale1,minimum-scale1,maximum-scale1,user-scalableno" /><meta charset"utf-8" /><title></…

keil5暗色主题配置

在keil文件目录下找到global.prop 将以下内容替换至该文件即可 # properties for all file types indent.automatic1 virtual.space0 view.whitespace0 view.endofline0 code.page0 caretline.visible0 highlight.matchingbraces1 print.syntax.coloring1 use.tab.color1 crea…

leetcode刷题日记:121. Best Time to Buy and Sell Stock( 买卖股票的最佳时机)

题目给了我们一组数prices&#xff0c;其中prices[i]表示第i天的股票价格&#xff0c;需要我们求出买卖股票所能获得的最大收益。 我们的第一想法就是从算出每一种买卖股票的情况然后求出里面的最大值&#xff0c;这样我们就能得到最大收益是多少&#xff0c;但是这种情况过于复…

LLM(四)| Chinese-LLaMA-Alpaca:包含中文 LLaMA 模型和经过指令微调的 Alpaca 大型模型

论文题目&#xff1a;《EFFICIENT AND EFFECTIVE TEXT ENCODING FOR CHINESE LL AMA AND ALPACA》 ​论文地址&#xff1a;https://arxiv.org/pdf/2304.08177v1.pdf Github地址&#xff1a;https://github.com/ymcui/Chinese-LLaMA-Alpaca 一、项目介绍 通过在原有的LLaMA词…

Lua的Resty-Request库写的一个简单爬虫

文章目录 准备工作编写爬虫运行爬虫代码分析拓展功能总结 &#x1f389;欢迎来到AIGC人工智能专栏~Lua的Resty-Request库写的一个简单爬虫 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&#xff1a;IT陈寒的博客&#x1f388;该系列文章专栏&#xff1a;AIGC人工智…

Databend 与海外某电信签约:共创海外电信数据仓库新纪元

为什么选择 Databend 海外某电信面临的主要挑战是随着业务量的增加&#xff0c;传统的 Clickhouse Hive 方案在数据存储和处理上开始显露不足。 原来的大数据分析采用的 Clickhouse Hive 方案进行离线的实时报表。但随着业务量的上升后&#xff0c;Hive的数据存储压力变大&…

HTTP代理与SOCKS5代理,有什么区别?

在数字通信领域&#xff0c;数据安全和匿名性都是非常重要的指标。互联网的不断发展催生了几种协议&#xff0c;每种协议都有独特的优势和挑战。其中&#xff0c;SOCKS5 代理、HTTP代理最为广泛使用&#xff0c;下面给大家一起讨论&#xff0c;HTTP代理与SOCKS5代理&#xff0c…

[文件读取]coldfusion 文件读取 (CVE-2010-2861)

1.1漏洞描述 漏洞编号CVE-2010-2861漏洞类型文件读取漏洞等级⭐⭐漏洞环境VULFOCUS攻击方式 描述: Adobe ColdFusion是美国Adobe公司的一款动态Web服务器产品&#xff0c;其运行的CFML&#xff08;ColdFusion Markup Language&#xff09;是针对Web应用的一种程序设计语言。 A…

市场行情回暖、利好月来袭,Web3 广告业领头羊 Verasity 或迎爆发

随着区块链技术的普及和发展&#xff0c;越来越多的行业正在被区块链技术所重塑&#xff0c;例如金融、游戏行业等&#xff0c;而数字广告行业的结构和运作方式也正在被区块链技术所重塑。 众所周知&#xff0c;传统数字广告行业往往存在着信息不对称、广告欺诈、数字隐私等问题…

《008.SpringBoot之教务系统》【界面简洁功能简单】

《008.SpringBoot之教务系统》【界面简洁功能简单】 项目简介 [1]本系统涉及到的技术主要如下&#xff1a; 推荐环境配置&#xff1a;DEA jdk1.8 Maven MySQL 前后端分离; 后台&#xff1a;SpringBootMybatis; 前台&#xff1a;JSPBootStrap; [2]功能模块展示&#xff1a; 管…

顺序表和链表

目录 1.线性表 2.顺序表 2.1 概念及结构 2.2 接口实现 2.3 顺序表的问题及思考 3.链表 3.1 链表的概念及结构 3.2 链表的分类 3.3 链表的实现 3.4双向链表的实现 4.顺序表和链表的区别和联系 1.线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的…

OpenMediaVault控制台web页面密码重置

要重置 OpenMediaVault&#xff08;OMV&#xff09;Web 控制台的密码&#xff0c;可以使用 omv-firstaid 命令行工具中的相应选项。按照以下步骤进行操作&#xff1a; 以管理员权限登录到 OMV 的命令行界面&#xff08;通过 SSH 或直接登录&#xff09;。 ssh登陆到root用户 运…

在windows上利用vmware17 搭建centos7 mini版本服务器

安装centos7mini 修改名称和安装路径 也可以点击自定义硬件&#xff0c;进行硬件配置修改 设置内存 设置处理器 点击下图按钮进行设置 点击done 点击开始安装 点击设置root密码 设置成功&#xff0c;点击done &#xff0c;root密码设置的简单的话需要按两次done 等待安装完成…

软考系统分析师知识点集锦二:系统规划

一、系统规划的步骤 (1)初步调查:根据企业战略目标&#xff0c;分析企业现状以及系统运行状况。(2)确定系统目标:确定系统的服务范围质量等。(3)分析子系统的组成:做系统划分并指定子系统功能。(4)拟定系统的实施方案:分析子系统优先级,确定开发顺序。(5)进行可行性研究:编写可…