JavaScript中的原型和原型链

news2025/1/11 16:45:39

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

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前端面试题库

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智慧城市项目建设介绍

1. 项目建设背景 随着城市化进程的加速,城市发展面临着诸多挑战,如环境污染、城镇综合管理、经济发展布局等。为了应对这些挑战,智慧城市应运而生,成为城市发展的重要方向。智慧城市通过运用信息技术和智能化技术,实…

腾讯云标准型S5服务器五年优惠价格表(4核8G和2核4G)

腾讯云服务器网整理五年云服务器优惠活动 txyfwq.com/go/txy 配置可选2核4G和4核8G,公网带宽可选1M、3M或5M,系统盘为50G高性能云硬盘,标准型S5实例CPU采用主频2.5GHz的Intel Xeon Cascade Lake或者Intel Xeon Cooper Lake处理器,…

(六)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB

一、七种算法(DBO、LO、SWO、COA、LSO、KOA、GRO)简介 1、蜣螂优化算法DBO 蜣螂优化算法(Dung beetle optimizer,DBO)由Jiankai Xue和Bo Shen于2022年提出,该算法主要受蜣螂的滚球、跳舞、觅食、偷窃和繁…

libgdx实现雪花、下雪效果(二十三)

libgdx实现雪花、下雪效果(二十三) 转自:https://lingkang.top/archives/libgdx-shi-xian-xue-hua package effect;import com.badlogic.gdx.ApplicationAdapter; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.backends.lwjgl3.…

腾讯云4核8G和2核4G服务器五年优惠价格表

腾讯云百科整理五年云服务器优惠活动 txybk.com/go/txy 配置可选2核4G和4核8G,公网带宽可选1M、3M或5M,系统盘为50G高性能云硬盘,标准型S5实例CPU采用主频2.5GHz的Intel Xeon Cascade Lake或者Intel Xeon Cooper Lake处理器,睿频3…

【C++】join ()和detach ()函数详解和示例

简单的来说,join ()方法建立的线程具有阻碍作用,该线程不结束,另一些函数就无法运行。detach ()方法建立的线程,可以和另一些函数同时进行。下面以示例进行详细说明,以帮助大家理解和使用。 目录 join ()detach () jo…

Java —— 继承

目录 1. 为什么需要继承 2. 继承概念 3. 继承的语法 4. 父类成员访问 4.1 子类中访问父类的成员变量 1. 子类和父类不存在同名成员变量 2. 子类和父类成员变量同名 4.2 子类中访问父类的成员方法 1. 成员方法名字不同 2. 成员方法名字相同 5. super关键字 6. 子类构…

腾讯云CVM服务器5年可选2核4G和4核8G配置

腾讯云服务器网整理五年云服务器优惠活动 txyfwq.com/go/txy 配置可选2核4G和4核8G,公网带宽可选1M、3M或5M,系统盘为50G高性能云硬盘,标准型S5实例CPU采用主频2.5GHz的Intel Xeon Cascade Lake或者Intel Xeon Cooper Lake处理器,…

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

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

工具: PowerShell常用命令

ISE: 打开ISE编辑器 echo: 输出一行信息 mkdir: 创建一个文件夹 mkdir ./MyPlugin文件相关处理 参考: powershell新手向,新建、删除文件及对文件添加内容 参考文档 PowerShell入门教程 语法、环境| Powershell 教程

软件测试基础1:认识软件及测试

功能测试能力:具备对所有软件的功能进行质量验证。 1什么是软件 分类 应用软件系统软件 软件:控制计算机硬件工作的工具。 2软件基本组成 3软件产生过程 4什么是软件测试 软件测试:使用技术手段验证软件是否满足使用需求。 5软件测试目的 减少软件…

智安网络|探索语音识别技术:优势与挑战的全面解析

语音识别技术是人工智能领域的重要应用之一,它通过将语音信号转化为文本,实现了人机交互的一种新形式。随着科技的不断发展,语音识别技术在各个行业中得到了广泛的应用,但同时也存在着一些优势和劣势。 首先,语音识别…

中国首个通过ASIL D认证的IP发布,国产芯片供应商的机会来了

来自智能汽车的“芯”安全需求正在快速爆发。 一方面,随着智能汽车ADAS的快速迭代与逐渐普及化,以及越来越多元化智能座舱功能的快速上车,由此带来的车辆信息安全场景也在与日俱增,例如云端链接、设备身份认证、自动驾驶安全保障…

产品的生命周期

** 没错,产品每次版本选代都是一次重生的机会,每次版本迭代都不亚于一次产品上线首发。 ** 一、产品上线首发 所谓万事开头难,产品上线首发的重要性不言而喻,产品给人的第一印象非常深刻,后期再去扭转非常困难&#…

Java入门篇 之 继承

本篇碎碎念:最近的课程遇到瓶颈了,看的时候感觉自己会了,但是结束仔细一回顾还是一知半解,一点一点来吧,基础必须要打好(自己给自己好的心里暗示,结局一定是好的) 今日份励志文案:慢慢改变,慢慢…

使用JDBC连接数据库出现The server time zone value ‘�й���׼ʱ��‘ is unrecognized 的解决方案

看到网上的大佬们说是引入的依赖版本太高所以导致了时区有问题 但是我把依赖的版本改低了还是报错 用另一种办法直接在配置文件中修改url然后成功解决 spring:datasource:url: jdbc:mysql://127.0.0.1:3306/datasource?useUnicodetrue&characterEncodingutf8&useSSL…

下载文件时的文件名中文乱码问题,文件名丢失

涉及到的java代码如下,下载的时候文件名为中文 package com.example.springboot.service.impl;import com.alibaba.excel.EasyExcel; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.StringU…

metinfo 6.0.0 任意文件读取漏洞复现

metinfo 6.0.0 任意文件读取漏洞复现 漏洞环境 环境为mrtinfo 6.0.0 漏洞存在的位置 通过代码审计发现在源代码的/app/system/include/module/old_thumb.class.php这个位置有着任意读取文件漏洞 漏洞点:http://127.0.0.1/metinfo_6.0.0//include/thumb.php 漏洞复现 访…

如何在微信内置浏览器内抓包

文章目录 使用环境&工具使用步骤1、手机USB连接上电脑,打开USB调试2、解压adb工具的压缩包,使用该工具连接上手机3、开启微信抓包4、电脑上打开chrome内核的浏览器或edge浏览器 使用环境&工具 windows电脑 安卓手机 adb工具 USB数据线 使用步骤…

2023.11.14使用bootstrap制作一个简洁的前端注册登录页

2023.11.14使用bootstrap制作一个简洁的前端注册登录页 比较简洁的登录页,主要是为自己开发的一些平台页面做测试用,前端具备功能如下: (1)输入用户名、密码,需补充后端验证代码。 (2&#xff…