【JS面向对象】JS对象原型

一篇文章带你搞懂JavaScript原型对象 文章目录原型对象`prototype`属性构造函数、实例、原型三者之间的关系属性成员的搜索原则:==原型链==实例对象读写原型对象成员更简单的原型语法原生对象的原型原型对象的问题原型对象使用建议原型对象的作用:共享数据,节省内存空间__proto__与prototype区分小案例案例:随机方块补充:把局部变量变成全局变量方法:把局部变量给window案例实现 原型对象 prototype属性 Javascript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象。 这个对象的所有属性和 阅读详情

JS对象原型

原型是 JS 中对象相互继承特性的机制,这里将解释什么是原型,以及原型链的工作原理、如何为一个对象设置原型,最后,会分析基于原型的继承机制。

1.原型与原型链

这里创建一个对象:

const myObject = {
  city: "bj",
  greet() {
    console.log(`来自 ${this.city} 的问候`);
  },
};
myObject.greet(); // 来自 bj 的问候

它具有数据属性 city 和方法 greet()。

当在控制台中输入 myObject. 时,可以看到该对象下可用的一系列属性:
在这里插入图片描述
但这些方法中,很多都不是我们定义的,现在尝试访问其中一个:

myObject.toString(); // "输出[object Object]"

发现其可以成功调用,那么这些额外的属性,是从哪里来的?

在 JS 中,所有对象均有一个内置属性,其被称为它的 prototype (原型)。它本身是一个对象,因此,原型对象也会有其自己的原型。

每当定义一个对象(函数也是对象)时,就会生成一个__proto__属性,被称为隐式原型;这个__proto__属性指向的是这个对象的构造函数的 prototype属性,其被称为显式原型。

当访问一个对象的属性或方法时,首先对象会从自身去找,如果找不到,就会往原型中去找,即__proto__,也就是它构造函数的 prototype 中。如果原型中找不到(即构造函数中也没有该属性),因为构造函数也是对象,也有__proto__,就会往原型的原型上去找…这样就形成了链式的结构,称为原型链,本质描述的是对象的一种继承关系!

因此在上面的代码中,浏览器做了以下工作:

  • 在 myObject 中寻找 toString 属性
  • myObject 中找不到 toString 属性,故在 myObject 的原型对象中寻找 toString
  • 其原型对象拥有这个属性,然后调用它。

那么 myObject 的原型是什么?可以使用 Object.getPrototypeOf() 函数来查询:
在这里插入图片描述
可以看到是一个对象,实际上,这个对象叫 Object.prototype,它是最基础的原型,所有对象默认都拥有它。Object.prototype 的__proto__属性是 null,即,它位于原型链的终点:
在这里插入图片描述
但需要注意的是,一个对象的原型并不总是 Object.prototype,比如:

const myDate = new Date();
let object = myDate;

do {
  object = Object.getPrototypeOf(object);
  console.log(object);
} while (object);

// 输出为:
// Date.prototype
// Object { }
// null

在这个例子中,创建了一个 Date 对象,然后遍历了它的原型链并输出了原型链上的原型。其原型链如下:
在这里插入图片描述
可以看到,如果调用 Date 类型常用的方法,如:myDate.getMonth()。实际上调用的是 Date.prototype 上的方法。

实际上,如果我们顺着上面 myObject 的例子继续看下去,我们会看到更有意思的情况:

首先我们明确一点,__proto__属性为空的原型就是 Object.prototype,即最基础的原型。

当我们定义一个函数时,可以看到这个函数的原型:

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/a6cca540f41842c499a6fe63bbeb24f3.png
即 f ()

而看下面这张图:
在这里插入图片描述

由前面的内容,我们知道,myObject 的 原型就是 Object.prototype ,而如果我们继续看下去,Object.prototype 同样有构造函数,而且这个构造函数是函数类型,进一步地,这个构造函数也有原型,其原型就是函数原型,而函数原型作为一个对象,其同样拥有 __proto__属性,且它的 __proto__属性指向的是 Object.prototype!

也就是下面这张图:

在这里插入图片描述
由此,还存在下面这几个比较有意思的等式:

Function.__proto__.__proto__ === Object.prototype
Function.__proto__ === Function.prototype
Object.__proto__.__proto__ === Object.prototype
Object.__proto__ === Function.prototype

2.属性遮蔽

当我们在对象中定义了一个属性,而在该对象的原型中也存在一个同名的属性,会发生什么呢?

const myDate = new Date(1995, 11, 17);

console.log(myDate.getYear()); // 95

myDate.getYear = function () {
  console.log("别的东西!");
};

myDate.getYear(); // '别的东西!'

基于上面对原型链的描述,这应该是可以预测的。当我们调用 getYear() 时,浏览器首先在 myDate 中寻找具有该名称的属性,如果 myDate 没有定义该属性,才检查原型。因此,当我们给 myDate 添加 getYear() 后,就会调用 myDate 中的版本。

这就叫做属性的遮蔽。

3.设置原型

在 JS 中,有多种设置对象原型的方法,这里主要介绍两种:

  1. Object.create()
  2. 构造函数
3.1 使用Object.create

例:

const personPrototype = {
  greet() {
    console.log("hello!");
  },
};

const carl = Object.create(personPrototype);
carl.greet(); // hello!

在这个例子中,创建了一个 personPrototype 对象,它有一个 greet() 方法。然后我们使用 Object.create() 来创建一个以 personPrototype 为原型的新对象。

现在我们可以在新对象上调用 greet(),而原型提供了这个方法的实现。(继承机制的体现!)

3.2 使用构造函数

在 JavaScript 中,所有的函数都有一个名为 prototype 的属性。当你调用一个函数作为构造函数时,这个属性被设置为新构造对象的原型,即该对象的显式原型。(按照惯例,该对象的 __proto__ 的属性会指向这个属性!)。

因此,如果我们设置了一个构造函数的 prototype,我们可以确保所有用该构造函数创建的对象都被赋予该原型:

const personPrototype = {
  greet() {
    console.log(`你好,我的名字是 ${this.name}!`);
  },
};

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

Object.assign(Person.prototype, personPrototype);
// 将Person函数的prototype属性赋为我们创建的对象或
// Person.prototype.greet = personPrototype.greet;

可以看到这里:

  • 创建了一个 personPrototype 对象,其中实现了输出名字的 greet() 方法
  • 创建了一个 Person() 构造函数,其中初始化了要创建人物对象的名字

在这段代码之后,使用 Person() 创建的对象将获得 personPrototype 作为其原型,其中自动包含 greet 方法。如下:

const reuben = new Person("Reuben");
reuben.greet(); // 你好,我的名字是 Reuben!即调用了其构造函数原型上的方法!

这也解释了为什么我们之前说 myDate 的原型被称为 Date.prototype,因为它是 Date 构造函数的 prototype 属性。

4.自有属性

在上面的例子中,使用 Person 构造函数创建的对象有两个属性:

  • name 属性,在构造函数中设置,在 Person 对象中可以直接看到
  • greet() 方法,在原型即 Person.prototype 中实现

这是一种非常常见的模式,即:方法是在原型上定义的,但数据属性是在构造函数中定义的。

这是因为方法通常对我们创建的每个对象都是一样的,而我们通常希望每个对象的数据属性都有自己的值(就像这里每个人都有不同的名字)。

而这些这就在对象中定义的属性,例如这里的 name,被称为自有属性,在 JS 中,我们可以用静态方法 Object.hasOwn() 来检查某一个属性是否是自有属性。

const irma = new Person("Irma");

console.log(Object.hasOwn(irma, "name")); // true
console.log(Object.hasOwn(irma, "greet")); // false

实际上,非静态方法 Object.hasOwnProperty() 也可以判断。但还是推荐使用静态方法 Object.hasOwn()。

5.原型与继承

原型是 JavaScript 的一个强大且非常灵活的功能,使得重用代码和组合对象成为可能。

特别是它们支持某种意义的继承。继承是面向对象的编程语言的一个特点,它让程序员表达这样的想法:系统中的一些对象是其他对象的更专门的版本。

例如,如果我们正在为一所学校建模,我们可能有教授 和学生 :他们都是人,所以有一些共同的特征(例如,他们都有名字),但每个人都可能增加额外的特征(例如,教授有一个他们所教的科目),或者可能以不同的方式实现同一个特征。在一个 OOP 系统中,我们可以说教授和学生都继承自人。

你可以看到在 JavaScript 中,如果 Professor 和 Student 对象具有原型 Person,那么他们可以继承共同的属性,同时增加和重新定义那些需要不同的属性。

首先整理一下相关概念:

  • 构造函数:在 JavaScript 中,构造函数可以实现类的定义,帮助我们在一个地方描述类的“形状”,包括定义类的方法。不过,原型也可以用于实现类的定义。例如,如果一个方法定义于构造函数的 prototype 属性中,那么所有由该构造函数创造出来的对象都可以通过原型使用该方法,而我们也不再需要将它定义在构造函数中。
  • 原型链:原型链很自然地实现了继承特性。例如,如果我们由 Person 原型构造了一个 Student 类,那么我们可以继承 Person 类的 name 属性,重写 introduceSelf() 方法。

而实际上,JS 中的继承特性与基于类的面向对象编程之间有所不同,下面就来探讨一下二者的区别。

首先,在基于类的面向对象编程中,类与对象是两个不同的概念,对象通常是由类创造出来的实例。由此,定义类的方式(定义类的语法)和实例化对象的方式(构造函数)也是不同的。而在 JavaScript 中,我们经常会使用函数或对象字面量创建对象,也就是说,JavaScript 可以在没有特定的类定义的情况下创建对象。相对于基于类的面向对象编程来说,这种方式更为轻量,帮助我们更为方便地使用对象。

其次,尽管原型链看起来很像是继承的层级结构,并且在某些方面,原型链的行为与继承的行为也很类似,但是在其他方面,二者之间仍然存在区别。在继承方式下,当一个子类完成继承时,由该子类所创建的对象既具有其子类中单独定义的属性,又具有其父类中定义的属性(以及父类的父类,依此类推)。而在原型链中,每一个层级都代表了一个不同的对象,不同的对象之间通过 __proto__ 属性链接起来。原型链的行为并不太像是继承,而更像是委派(delegation)。委派同样是对象中的一种编程模式。当我们要求对象执行某项任务时,在委派模式下,对象可以自己执行该项任务,或者要求另一个对象(委派的对象)以其自己的方式执行这项任务。在许多方面,相对于继承来说,委派可以更为灵活地在许多对象之间建立联系(例如,委派模式可以在程序运行时改变、甚至完全替换委派对象)。

尽管如此,构造函数和原型仍然可以在 JavaScript 中实现基于类的面向对象编程特性。但是直接使用构造函数和原型去实现这些特性(例如继承)仍是棘手的,因此,JavaScript 提供了一些额外的特性,这些特性在原型这一模型之上又抽象出一层模型,将基于类的面向对象编程中的概念映射到原型中,从而能够更为直接地在 JavaScript 中使用基于类的面向对象编程中的概念。实际上,就是 ES6 中新增的 class 语法糖!

那么,JS 中有哪些实现继承的方法呢?

6.JS中实现继承的方法

  1. 构造函数继承:在⼦对象的构造函数中,通过 call 或者 apply 调⽤⽗对象的构造函数来继承⽗对象的属性
  2. 原型继承:即把⼦对象的原型prototype 设置为⽗对象的一个实例
  3. 组合继承:组合继承实际上是上面两种方法的结合,⼀般我们会通过构造函数来继承属性,通过原型来继承⽅法。
  4. 最后就是ES6新增了class,可以通过extends来实现继承,但本质上仍然是构造函数和原型的继承。

7.实例

…

JavaScript中对象原型的探索与应用 本文深入探讨了JavaScript中对象原型的概念,通过示例展示了如何在对象中添加属性,以及原型链如何影响对象属性的继承。文章详细解释了原型、原型链以及如何通过原型扩展对象功能,还介绍了无原型对象的创建方法。 阅读详情

相关推荐

[js高手之路]图解javascript的原型(prototype)对象,原型链实例

下面小编就为大家带来一篇[js高手之路]图解javascript的原型(prototype)对象,原型链实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

JavaScript原型对象---知识总结

任何一个JavaScript对象(一般有对花括号)都有一个原型对象,这个原型对象是JavaScript语言内置的,JavaScript对象可以使用原型对象的属性和方法。

qq_47286790的博客 3671

从KVM虚拟化到Openstack云化架构综述

目录 摘要 OpenStack的虚拟化技术 OpenStack架构介绍 Nova Swift KeyStone Neutron Glance Cinder Ceilometer Heat 摘要 这两年的工作中,接触到公有云和私有云的项目还不少。起初对于Openstack的了解,仅停留在其几大组件的交互上,如Nova、Neutron、Glance等,以及对各大云厂商功能点上...

liyunpeng229的博客 2051

JS-原型对象

1. 原型prototype:创建的每一个函数,解析器都会向函数中添加一个属性prototype 这个属性对应着一个对象,这个对象就是原型对象。 如果函数作为普通函数调用prototype没有任何作用, 当函数以构造函数调用时,它所创建的对象都会有一个隐含的属性,指向该构造函数的原型对象,可以通过__proto__来访问该属性。 原型对象就相当一个公共的区域,所有同一个类的实例都可以访问这个原型对象。可以将对象中共有的内容,统一设置到原型对象中。不用分别为每一个对象添加也不会影响到全局作用域。

xpmhhh的博客 2515

避开集成插件!手把手教你用URL登录实现Finereport与致远OA的无缝跳转

本文详细介绍了如何通过URL登录机制实现Finereport与致远OA的无缝跳转,无需复杂插件配置。文章涵盖用户体系同步、环境配置、URL登录核心设置及安全加固方案,特别适合企业数字化转型中BI工具与OA系统的轻量化集成需求。

weixin_29215815的博客 75

Kali Linux实战:用Impacket的secretsdump.py快速提取Windows域控哈希(附避坑指南)

本文详细介绍了如何在Kali Linux中使用Impacket的secretsdump.py脚本快速提取Windows域控哈希,包括环境准备、原理剖析、实战操作及常见问题解决方案。特别适合CTF竞赛和网络信息安全爱好者学习,提升渗透测试效率。

weixin_33670786的博客 410

JavaScript——原型对象(一)

JavaScript原型对象的简单介绍,构造函数、实例对象和原型对象三者的关系。

zg0601的博客 1697

KEGG数据库与KAAS工具:基因功能注释的实用指南

本文提供了使用KEGG数据库与KAAS工具进行基因功能注释的完整实用指南。详细阐述了如何从准备基因或蛋白序列开始,通过KAAS服务器获取KEGG Orthology(KO)编号,并解读注释结果。文章进一步介绍了如何利用KOBAS工具进行通路富集分析,将定性观察转化为定量洞察,并分享了提高注释准确率、处理大数据集及使用API等避坑技巧与高阶方法,为基因组学、转录组学研究者奠定坚实的数据分析基础。

weixin_29292535的博客 390

JS面向对象的核心概念:封装、继承和多态——什么是封装?什么是继承和多态。什么是对象原型,它是怎么通过对象原型实现封装和继承的?什么又是原型链,又怎么通过原型链实现多态?

封装:将数据和行为封装在对象中,通过接口与外部交互,隐藏内部细节。继承:子类可以继承父类的属性和方法,避免重复代码。多态:子类可以重写父类的方法,同样的方法在不同对象上表现出不同的行为。对象原型:对象通过原型实现继承,每个对象都有一个原型,方法和属性通过原型链共享。原型链:对象通过原型链进行属性和方法的查找,沿着链条直到。

m0_73487394的博客 1104

卡门涡街可视化实战:从网格加密策略到动画后处理技巧

本文详细介绍了利用ANSYS Fluent进行卡门涡街可视化模拟的全流程,包括网格加密策略、求解器设置、涡街捕捉及动画后处理技巧。通过计算流体力学(CFD)方法,帮助工程师和研究人员高效模拟圆柱绕流现象,优化工程设计。

weixin_29309785的博客 414

非易失存储器读写

24C256、IIC_SCL、IIC_SDA

CT_1104的专栏 2986

JavaScript中的 对象基础、对象原型、面向对象编程基本概念和类

name 和 age 就是person对象的 属性,bio和introduceSelf就是person对象的 方法。点表示发就是通过 . + 属性名 或 . + 方法名 的格式访问对象的属性值或者 执行对象中的方法。但是这样,我们就必须创建一个空对象,初始化它,并返回它,就有点冗长,更好的方法就是使用。在上面的 两个对象中,this代表的值不同,在 person1 中。我们希望有一种方法可以创建任意多个对象,只要更新不同属性的值。那么 person 就是对象,一个空的对象。

qq_64745318的博客 794

一篇关于轴承故障诊断的综述

在设备的故障检测中,有约30%-40%的设备故障是由轴承故障引起的,因此本文将列举有关检测轴承故障使用到的相关数据集,模型和算法。 数据集 现有的数据集,普遍由固定在电机马达上的两个震动检测器获得,并根据需要,分离震动数据在时域和频域上的特征以供网络模型学习。 不同的数据集,区别在于,检测的马达转速不同,环境不同,取样频率不同,一段样本的时长不同等等 (1)Case Western Reserve University (CWRU) Dataset 该数据集拥有多种数据,测量的时候,通过改变轴承.

weixin_42036144的博客 2万+

JS进阶(三):面向对象、面向过程、原型、constructor属性、对象原型、原型链

面向过程,就是按照我们分析好的步骤,按照步骤解决问题。作用:该属性指向该原型对象的构造函数。每个原型对象里面都有个constructor属性。__proto__串起来的链。面向对象是以功能来划分问题,而不是步骤。(constructor构造函数)

2303_80098652的博客 351

“华为杯“第十四届中国研究生数学建模竞赛-E题:多波次导弹发射中的规划问题(续)(附MATLAB代码实现)

将最长暴露时间的发射装置按照“优先隐蔽于转载地”,即增加该种发射装置的隐蔽时长,从而达到缩短最长暴露时间的目的。8.2 模型建立。

getusushu的博客 298

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

JavaScript面向对象学习对象原型、原型、原型链(二)

原型:一般情况下,公共属性定义到构造函数里面, 公共的方法放到原型对象身上

总结前端开发中遇到的问题,分享前端知识 197

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

你不知道的javascript

最近笔者使用node.js完成了一个小型项目,在javascript的泥坑里面摸爬滚打了一番,感触颇深。Javascript会给习惯于传统面向对象模式的开发人员,带来很多意想不到的障碍。这些问题基本上是因为误解了javascript的设计导致的。 如果有本书能把js的这些槽点、另类之处,一次性说个明白就好了。还真是有,图灵就出版了一本《你不知道的javascript》。 图灵出版的这本《你不知道的javascript》三卷。 https://pan.baidu.com/s/1K2dW_syvf5LFDJYF

weixin_35597398的博客 5316

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

javaScript中的面向对象与原型

js是面向函数编程,更多的是面向过程,但是vue等框架更是面向对象。

m0_62378126的博客 831

【JavaScript】JavaScript 进阶(编程思想、构造函数、原型对象)

【JavaScript】JavaScript 进阶(编程思想、构造函数、原型对象)

“欢迎来到我的个人博客,我是一名热爱前端技术、致力于提升用户体验的前端开发工程师。” 921

javascript 面向对象基础(二) 包装对象原型链

/** *面向对象高级部分 * 不要修改或者添加系统对象下面的方法和属性 * * 包装对象 * 基本类型都有自己对应的包装对象 * null undefined没有 * 原型链 * 实例对象与原型之间的链接,叫做原型链 * _proto_(隐式链接) * Object对象类型是原型链的最外层: Object.prototype */ //

凯子的专栏 352

【JavaScript】ES6之面向对象的对象、类、构造函数、原型对象、对象原型、原型链

ES6面向对象1、面向对象1.1、对象1.2、类1.2.1、创建类1.2.2、构造函数1.2.3、类中添加方法1.3 、类的继承1.4、super关键字1.4.1、调用父类的构造函数1.4.2、调用父类的普通函数1.4、三个注意点2、构造函数和原型2.1、概述2.2、构造函数2.2.1、静态成员和实例成员2.2.2、构造函数的问题2.3、构造函数原型 prototype2.4、对象原型 __ proto __constructor 构造函数2.6、构造函数、实例、原型对象三者关系2.7、原型链查找规则2.8

GY的博客 2047

面向对象编程--JS原型和原型链

JavaScript 的继承和属性查找机制完全依赖原型和原型链,理解它们是掌握 JS 面向对象编程的关键!​是它实现继承和属性查找的核心机制。理解它们,才能真正掌握 JavaScript 的面向对象编程。JavaScript 是一门基于原型的语言,​。本质上是语法糖,底层仍然是基于原型的继承。dog (Dog 实例)dog (Dog 实例)对象自身 → 对象的。

hyk15543的博客 895

对前端js高级面向对象的理解? 如何理解前端js中的内置对象、 对象原型、原型链?

对象是一个包含相关数据和方法的集合(通常由一些变量和函数组成,我们称之为对象里面的属性和方法)对象是javascript中的一个重要的概念,甚至有“JavaScript 中万物皆是对象”的说法。内置对象:指JS语言自带的一些对象,这些对象供开发者使用,并提供了一些常用的或者是最基本而必要的功能(属性和方法)内置对象最大的有点就是帮助我们快速开发JavaScript提供了多个内置对象:Math、Date、Array、String等Math。

2301_78320134的博客 1236

JS原型和原型链

这周主要复习了JS高级相关的知识,但是还没复习完,下周把JS高级和ES6再复习复习。

2403_87892684的博客 988

JS模拟面向对象,对象原型,JSON,with语句,for in 语句

// 定义类,定义函数 function Person () { this.name ="dub"//公有的属性 age = 100;//私有属性 //公有的方法 this.hh = function () { alert("hh"); //私有的方法 kk = function () { alert("ll"); }} } //创建对象 var P = ne

why 353

js进阶3

2501_93485759的博客 116
上一篇: 【前端模块化】JS模块化思想以及相关规范(CommonJS、ES module)
下一篇: 【前端布局规范与方案】CSS常见布局方式以及其实现方法
cannotbecounted
博客等级 码龄7年 101粉丝 59原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值