(day 15)JavaScript学习笔记(对象3)

概述

        这是我的学习笔记,记录了JavaScript的学习过程。在写博客的时候我会尽量详尽的记录每个知识点。如果你完全没接触过JavaScript,那么这一系列的学习笔记可能会对你有所帮助。

        今天继续学习对象,主要是Object.create()、原型链、修改原型指向等。

1.Object.create()

        Object.create()可以让一个对象继承自另一个对象,新的对象拥有它继承对象的所有属性,并且还能保留自己的特有属性,如下代码示例:        

// 创建构造函数
function Student(name, id) {
  this.name = name;
  this.id = id;
  this.eat = function () {
    console.log(this.name + "吃饭");
  };
}

//创建实例对象stu1
var stu1 = new Student("小慈", 20240001);
console.log(stu1);

//遍历对象stu1的属性
for (key in stu1) {
  console.log(key);
}

//创建一个对象,继承自stu1
var monitor = Object.create(stu1);
console.log(monitor); //Student {}

        如上代码,我们创建了一个monitor对象,继承自stu1。上面代码stu1的属性遍历结果是如下:

name
id
eat

        我们再遍历一下monitor的属性,如下代码:

//遍历对象monitor的属性
for (key in monitor) {
  console.log(key);
}

       monitor属性遍历的结果如下:

name
id
eat

         从上我们可以看出,monitor属性与stu1一致,它的属性完全继承自stu1.

        用Object.getOwnPropertyNames可以获取对象自己的属性,我们分别获取一下stu1和monitor的自己的属性,如下代码:

console.log(Object.getOwnPropertyNames(stu1)); //(3) ['name', 'id', 'eat']
console.log(Object.getOwnPropertyNames(monitor)); //[]

        我们可以看到stu1是有三个自己的属性,monitor没有自己的属性,因为它是继承自stu1的,所以没有自己的属性,我们试一下打印一下monitor的name属性值,如下:

console.log(monitor.name); //小慈

        它的属性值跟stu1一样,我们接下来给monitor修改属性,如下代码:

//修改属性
monitor.name = "小会";
monitor.id = 20240010;
console.log(monitor); //Student {name: '小会', id: 20240010}
//获取对象自己的属性
console.log(Object.getOwnPropertyNames(monitor)); //(2) ['name', 'id']

        我们看到修改了 monitor对象中name和id的属性值,它就有的自己的属性,我们再调用一下eat方法试试:

//调用eat方法
monitor.eat(); //小会吃饭  说明this指向了monitor

        可以看到eat方法运行结果是小会吃饭,不是小慈吃饭,说明this指向了monitor。

2. 原型链

        JavaScript中的每个对象都有一个内部链接指向它的原型对象。当试图访问一个对象的属性时,如果该对象自身没有这个属性,那么JavaScript会在对象的原型上查找这个属性,这就是原型链。如果原型对象自身也没有这个属性,那么会继续在原型对象的原型上查找,以此类推,直到找到属性或者到达原型链的末尾(通常是null)。

        在JavaScript中,几乎所有的对象都继承自Object.prototype。Object.prototype是所有对象的最终原型。这意味着,如果你尝试访问一个对象上不存在的属性或方法,JavaScript最终会在Object.prototype上查找。如果Object.prototype上也没有找到,那么会返回undefined。

        简单来说就是每个对象的原型都会有一个上层的原型,直到遇到null,这种链式继承下来的原型就构成了原型链,JavaScript中最顶层的对象是Object,它的原型是Object.prototype,但是它的原型的原型就是null,这样就达到了原型链的顶端。

        下面代码演示一下,下面代码是获取对象monitor(monitor是我们上一个小节中定义的对象)的原型,并赋值给变量protoOfMonitor:

//Object.getPrototypeOf获取对象的原型
var protoOfMonitor = Object.getPrototypeOf(monitor);
console.log(protoOfMonitor);

        上面代码运行结果如下,因为monitor继承自stu1,所以它的原型指向的是stu1。

        我们进一步获取protoOfMonitor的原型,并赋值给变量protoOfStu1,如下代码示意:

var protoOfStu1 = Object.getPrototypeOf(protoOfMonitor);
console.log(protoOfStu1);

        运行结果如下图所示,因为stu1是用构造函数创建的,所以它的原型指向的是构造函数:

        我们再进一步获取 protoOfStu1的原型,并赋值给变量protoOfStudent,如下代码所示:

var protoOfStudent = Object.getPrototypeOf(protoOfStu1);
console.log(protoOfStudent);

        运行结果如下,因为构造函数的原型是Object对象,所以它的原型指向的是Object:

 

        到这一层已经到了Object对象了,我们再进一步获取protoOfStudent的原型,如下代码:

var protoOfObj = Object.getPrototypeOf(protoOfStudent);
console.log(protoOfObj); 

        运行结果为:null

        至此,我们已经达到了原型链的最顶端了。这就是对象的原型链。

3.修改原型指向

        修改原型的指向,可以改变对象的继承关系,从而获取不同的属性和方法。这通常是通过改变构造函数的prototype属性来实现的。如下代码示例:        

function Person() {}

//给Person添加原型方法
Person.prototype.sayHello = function () {
  console.log("你好,我是" + this.name);
};
//给Person添加原型属性
Person.prototype.species = "人类";

//定义一个构造函数Students
function Students(name, id) {
  this.name = name;
  this.id = id;
  this.sayGood = function () {
    console.log("我很好!");
  };
}

//创建实例对象stu2
var stu2 = new Students("小雪", 20240030);
console.log(stu2.name, stu2.id); //可以访问name和id属性,输出:小雪 20240030
stu2.sayGood(); //调用sayGood方法,输出:我很好!
console.log(stu2.species); //没有species,返回:undefined
//stu2.sayHello();
//调用sayHello方法,运行报错:Uncaught TypeError: stu2.sayHello is not a function

//查看stu2的原型
console.log(Object.getPrototypeOf(stu2));

        上面的例子中,我们先创建了一个Person构造函数,并给他增加了原型方法sayHello和原型属性species,我们再创建一个Students构造函数并创建实例对象stu2,我们访问stu2的name和id的属性都能访问,stu2也可以调用sayGood方法,说明stu2继承了构造函数的属性和方法,我们访问stu2的species属性时,会返回undefined,调用stu2的sayHello方法时会报错,因为species属性sayHello方法是Person构造函数的原型属性和方法,stu2与Person构造函数没有继承关系。我们再查看stu2的原型,返回的是如下的结果,可以看出来,stu2的原型指向的是Students构造函数。

        接下来我们来修改原型指向,让stu2也具有species属性sayHello方法,并且我们再访问之前的那些属性和方法,如下代码:

//修改stu2的原型指向
Object.setPrototypeOf(stu2, Person.prototype);

console.log(stu2.name, stu2.id); //依然可以访问name和id属性,输出:小雪 20240030
stu2.sayGood(); //调用sayGood方法,输出:我很好!

stu2.sayHello(); //调用sayHello方法,输出:你好,我是小雪
console.log(stu2.species); //输出:人类

        我们可以看到,修改原型指向后,stu2具有了species属性sayHello方法,并且还保留了原来的属性和方法,我们再看一下现在的stu2的原型,如下代码:

//查看stu2的原型
console.log(Object.getPrototypeOf(stu2));

        运行结果如下:

        可以看到,stu2的原型指向已经发生改变。最后我们再用绝对等于判断一下stu2的原型与Person的原型是否相等。如下代码:        

//判断stu2的原型与Person的原型是否相等
console.log(Object.getPrototypeOf(stu2) === Person.prototype); //true

         可以看到返回了true,说明他们是完全相等的。

        以上便是今天的学习内容,如果对你有所帮助,请点个赞再走吧。

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

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

相关文章

IPv6介绍

IPv6(互联网协议版本6)是用于互联网的最新网络层通信协议,旨在解决IPv4地址耗尽的问题,并提供了多项改进。IPv6于1998年由互联网工程任务组(IETF)标准化,作为IPv4的后继者。下面是IPv6的一些详细…

Linux - 应用层HTTPS、传输层TCP/IP模型中典型协议解析

目录 应用层:自定制协议实例 HTTP协议首行头部空行正文http服务器的搭建 HTTPS协议 传输层UDP协议TCP协议 应用层: 应用层负责应用程序之间的沟通—程序员自己定义数据的组织格式 应用层协议:如何将多个数据对象组织成为一个二进制数据串进行…

【文末附gpt升级4.0方案】英特尔AI PC的局限性是什么

为什么要推出英特尔AI PC? 英特尔AI PC的推出无疑为AIGC(生成式人工智能)的未来发展开启了一扇新的大门。这种新型的计算机平台,通过集成先进的硬件技术和优化的软件算法,为AIGC提供了更为强大和高效的支持&#xff0…

【探讨】基于卷积神经网络深度学习模型的光场显微三维粒子空间分布重建

光场显微粒子图像测速技术通过单光场相机即可实现微尺度三维速度场的测量,但单光场相机角度信息有限,导致粒子重建的轴向分辨率低、重建速度慢。基于此,提出一种基于卷积神经网络深度学习模型的光场显微粒子三维空间分布重建方法,…

说说你对webpack的理解?解决了什么问题?

文章目录 一、背景二、问题三、是什么参考文献 一、背景 Webpack 最初的目标是实现前端项目的模块化,旨在更高效地管理和维护项目中的每一个资源 模块化 最早的时候,我们会通过文件划分的形式实现模块化,也就是将每个功能及其相关状态数据各…

深入理解:蓝绿部署与金丝雀部署

深入理解:蓝绿部署与金丝雀部署 深入理解:蓝绿部署与金丝雀部署蓝绿部署(Blue-Green Deployment)原理优缺点适用场景 金丝雀部署(Canary Deployment)原理优缺点适用场景 总结 深入理解:蓝绿部署…

便捷安全的移动支付方式:扫码登录与支付全面解析

随着移动支付的普及和便利性,扫码登录与支付作为一种快捷安全的支付方式,在各行各业得到了广泛应用。本文将深入探讨扫码登录与支付的原理、优势以及使用场景,帮助读者更好地了解这一便捷的移动支付方式。 ## 扫码登录与支付的原理 扫码登录…

MNN Session 之 CPU 算子(七)

系列文章目录 MNN createFromBuffer(一) MNN createRuntime(二) MNN createSession 之 Schedule(三) MNN createSession 之创建流水线后端(四) MNN Session 之维度计算(五…

Java 程序设计 4 数学函数、字符、字符串

数学函数 Math是final类,在java.lang.Math中,所有数学函数都是静态方法。 Math类中定义了常用的 数学常数 PI : 3.14159265358979323846E : 2.7182818284590452354 方法: 三角函数:sin, cos, tan, asin, acos, atan,toRadians,toD…

mysql分页查询多用GitCode平台

目录 一、在GitCode平台AI搜索结果(这个更优) 二、在百度搜索输入“mysql Java分页查询”的输出结果: 三、推荐的文章 四、GitCode的使用 1)如搜索jdk11可以直接下载jdk11的包 2)搜索开源项目 3)如搜…

爬虫分析-基于Python的空气质量数据分析与实践

概要 本篇文章利用了Python爬虫技术对空气质量网站的数据进行获取,获取之后把数据生成CSV格式的文件,然后再存入数据库方便保存。再从之前24小时的AQI(空气质量指数)的平均值中进行分析,把数据取出来后,对数据进行数据…

大数据分析-基于Python的电影票房信息数据的爬取及分析

概要 现如今,人民群众对物质生活水平的要求已不再局限于衣食住行,对于精神文化有了更多的需求。电影在我国越来越受欢迎,电影业的发展越来越迅猛,为了充分利用互联网技术的发展,掌握电影业的态势,对信息进行…

进程的终止

进程的退出(main函数的退出) main函数的返回值叫做进程的退出码,该退出码表示进程执行的情况。例如:一个函数返回一个值时,我们要知道函数的执行情况,可以去看函数的返回值。 例子: 1 #include…

Redis相关操作高阶篇--集群搭建

Redis相关操作大全一篇全搞定-CSDN博客 Redis集群 是一个由多个主从节点群组成的分布式服务器群,它具有复制、高可用和分片特性。Redis集群不需要seninel哨兵也能完成节点移除和故障转移的功能。需要将每个节点 设置成集群模式,这种集群模式没有中心节…

c++的学习之路:2、入门(1)

一、 C关键字 c的关键字要比c语言要多31个足足有63个,这里我只是了解了下每个有啥作用,具体使用方法以及更多的知识将在后续学习中,慢慢扩展使用,下方表格就是c的63个关键字 asmdoifreturntryautodoubleinlinetypedefdynamic_ca…

LeetCode题练习与总结:接雨水

一、题目 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例 1: 输入:height [0,1,0,2,1,0,1,3,2,1,2,1] 输出:6 解释:上面是由数组 [0,1,0,2,1,0,1,3…

【MySQL】3.1MySQL索引的介绍

目录 一、索引的概念 数据库索引 索引的作用 索引的副作用 索引创建的原则(应用场景) 适合建立索引 二、索引的分类和创建 1.普通索引 创建普通索引 1.1直接创建 1.2修改表结构的方式创建普通索引 1.3创建表时创建普通索引 2.唯一索引 2.1…

如何在Android设备上运行深度网络

返回:OpenCV系列文章目录(持续更新中......) 上一篇: 下一篇: 介绍 在本教程中,您将了解如何使用 OpenCV 深度学习模块在 Android 设备上运行深度学习网络。教程是为 Android Studio 2022.2.1 编写的。…

实时数仓之实时数仓架构(Doris)

目前比较流行的实时数仓架构有两类,其中一类是以Flink+Doris为核心的实时数仓架构方案;另一类是以湖仓一体架构为核心的实时数仓架构方案。本文针对Flink+Doris架构进行介绍,这套架构的特点是组件涉及相对较少,架构简单,实时性更高,且易于Lambda架构实现,Doris本身可以支…

c++编写菱形图和计算100~200之间的素数

c编写菱形图 #include <stdio.h> int main() {int i,j,k,n;printf("请输入n:\n");scanf("%d",&n);for(i1;i<n;i){for(k1;k<n-i;k)printf(" ");for(j1;j<2*i-1;j)printf("*");printf("\n");}for(i1;i<…