当前位置: 首页 > news >正文

原型、原型链、__proto__与prototype的区别、继承

一.什么是原型与原型链

根据MDN官方解释: JavaScript 常被描述为一种基于原型的语言——每个对象拥有一个原型对象[[Prototype]] ,对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype chain),它解释了为何一个对象会拥有定义在其他对象中的属性和方法。

以前可以通过__proto__访问原型,但现在它已经从相关web标准中被移除,后续可通过Object.getPrototypeOf(obj)来获取原型。在 javascript 中,函数可以有属性。每个函数都有一个特殊的属性叫作原型(prototype),而它主要是用作继承

二.原型的作用

之所以存在原型,是因为JS语言需要实现面向对象,而原型是面向对象的实现手段之一。一个能支持面向对象的语言必须做到一点:能判断一个实例的类型. 在JS中,通过原型就可以知晓某个对象从属于哪个类型,换句话说,原型的存在避免了类型的丢失。在使用方面,有了原型就可以抽离实例的公共方法到原型上,这样就避免了把方法放到实例中,从而减少了内存的消耗。

三.隐式原型和显示原型的区别

在过去我们常用__proto__表示隐式原型(它其实就是[[Prototype]])。用prototype代表显示原型。
每个对象(数组,对象,函数)都有自己的__proto__,通过__proto__可以添加数据到原型,也可以通过它一层一层查找数据。构造函数默认会有prototype属性,prototype属性是用来继承的,实例化之后__proto会指向构造函数的prototype。

四.JS的继承

父类

function Person(name) {this.name = namethis.say = function () {console.log('1 + 1 = 2')}this.colors = ["red", "blue", "green"];
}Person.prototype.listen = function () {console.log('エウテルペ')
}Person.prototype.sayName = function () { // 父类原型方法return this.name;};

4.1 原型继承

将父类的实例作为子类的原型

缺点:

  • 无法实现多继承,即一个子类不能同时继承多个父类
  • 所有实例共享同一个父类的原型,修改子类的原型会影响父类的原型
  • 创建子类实例时,无法向父类构造函数传参
// TODO:思路:将父类的实例作为子类的原型
function Student() {this.type = "学生"this.name = "张三"
}Student.prototype = new Person('人') //TODO:关键点 通过原型继承父类 =>无法实现多继承,即一个子类不能同时继承多个父类
Student.prototype.xx = 123
Student.prototype.fn = ()=>{}const zhangsan = new Student()
console.log(zhangsan);Person.prototype.eat = function () {console.log('吃东西')
}
console.log(zhangsan);// TODO:缺点
// 1 无法实现多继承,即一个子类不能同时继承多个父类
// 2 所有实例共享同一个父类的原型
function Student2() {this.type = "学生"this.name = "张三"
}
Student2.prototype = new Person('人2')
// 3 创建子类实例时,无法向父类构造函数传参
const lisi = new Student2()

4.2 构造继承

在子类的构造函数内部调用父类构造函数并改变构造函数的this指向。

缺点:

  • 父类原型上的属性没有继承过来
  • 因为原型没有继承过来所以无法实现函数复用,每个子类都有父类构造函数的副本,影响性能
  • 实例并不是父类的实例,只是子类的实例
// TODO:思路:在子类型的构造函数内部调用父类构造函数并改变构造函数的this指向。
function Student(name) {// this.person = new Person(name)Person.call(this,name) // TODO:关键点this.age = 16
}
Student.prototype.run = '跑路'
const lisi = new Student('李四') // 能实现多继承 可以向父类传递参数
// 优点
// 解决了所有实例共享同一个父类的原型,实现多继承,创建子类实例时,可以向父类传递参数
// TODO:缺点
// 1 父类原型上的属性没有继承过来
function Student2(name) {Person.call(this,name)this.age = 18
}
// 2 因为原型没有继承过来所以无法实现函数复用,每个子类都有父类构造函数的副本,影响性能// 3 实例并不是父类的实例,只是子类的实例(只是实例化了Student,根本就没有实例化Person)
const zhangsan = new Student('张大帅')

4.3 组合继承

顾名思义,组合继承就是将原型链继承与构造函数继承组合在一起,从而发挥两者之长的一种继承模式。

缺点:

  • 所有实例共享同一个父类的原型,修改子类的原型会影响父类的原型
  • 调用了两次父类的构造函数
// TODO:思路:顾名思义,组合继承就是将原型链继承与构造函数继承组合在一起,从而发挥两者之长的一种继承模式。
function Student(name, subName) {Person.call(this, name) // 构造继承 第一次调用构造函数this.subName = subName;
}
Student.prototype = new Person() // TODO:关键点 原型继承 第二次调用构造函数
// Student.prototype = Person.prototype
Student.prototype.constructor = Student // 组合继承需要修复构造函数指向?
Student.prototype.saySubName = function () { // 子类原型方法return this.subName;
}// 子类实例
let instance = new Student('王五', 'sisterAn')
instance.colors.push('black')
console.log(instance.colors) // ["red", "blue", "green", "black"]
console.log(instance.sayName()) // 王五
console.log(instance.saySubName()) // sisterAn
console.log(instance);let instance1 = new Student('赵六', 'sisterAn1')
console.log(instance1.colors) //  ["red", "blue", "green"]
console.log(instance1.sayName()) // 赵六
console.log(instance1.saySubName()) // sisterAn1
console.log(instance1);
// 优点:解决了构造继承的缺陷,可以继承原型属性/方法,实现复用
// TODO:缺点:调用了两次父类的构造函数

4.4 寄生组合继承

通过原型链的混成形式来继承方法,在组合继承的基础上.利用 Object.create() 将Person.prototype通过原型的方式继承给一个对象,这样的访问顺序就还是保持子类优先,同时后续添加原型也不会影响父类的原型

优点:

  • 解决了组合继承的缺陷,只调用一次父类的构造函数
  • 修改子类的原型,父类不变

补充

  • Student.prototype.isPrototypeOf(instance)
    • 用于检测构造函数Student.prototype是否存在于另一个对象instance的原型链上
  • instance instanceof Student
    • 用于检测实例对象instance的原型链上是否存在构造函数Student的 prototype。
// TODO:思路:通过原型链的混成形式来继承方法
function Student(name, subName) {Person.call(this, name) // 构造继承this.subName = subName;
}
// 用 Object.create() 将参数1通过原型的方式继承给参数2,这样的访问顺序就还是保持子类优先,同时后续添加原型也不会影响父类的原型
console.log(Object.create(Person.prototype));
Student.prototype = Object.create(Person.prototype, {varB : {value: null,enumerable: true,configurable: true,writable: true},doSomething : {value: function(){ // overrideA.prototype.doSomething.apply(this, arguments);// call super// ...},enumerable: true,configurable: true,writable: true}}); // TODO:关键点
Student.prototype.constructor = Student // 组合继承需要修复构造函数指向// 子类实例
let instance = new Student('王五', 'sisterAn')
instance.colors.push('black')
console.log(instance.colors) // ["red", "blue", "green", "black"]
console.log(instance.sayName()) // 王五
console.log(instance.doSomething())
console.log(instance);let instance1 = new Student('赵六', 'sisterAn1')
console.log(instance1.colors) //  ["red", "blue", "green"]
console.log(instance1.sayName()) // 赵六
console.log(instance1.doSomething())
console.log(instance1);
// 优点:解决了组合继承的缺陷,只调用一次父类的构造函数,原型链保持不变
// Student.prototype.isPrototypeOf(instance) true // 用于检测构造函数Student.prototype是否存在于另一个对象instance的原型链上
// instance instanceof Student // 用于检测实例对象instance的原型链上是否存在构造函数Student的 prototype。

4.5 ES6继承

可以理解ES6继承就是组合寄生继承的一个语法糖.

使用

class People {constructor(name) {this.name = name}run() { }
}// extends 相当于方法的继承
// 替换了上面的3行代码
class Man extends People {constructor(name) {// super 相当于属性的继承// 替换了 People.call(this, name)super(name)this.gender = '男'}fight() { }
}

extends 继承的核心代码如下,其实和寄生组合式继承方式一样

function _inherits(subType, superType) {// 创建对象,Object.create 创建父类原型的一个副本// 增强对象,弥补因重写原型而失去的默认的 constructor 属性// 指定对象,将新创建的对象赋值给子类的原型 subType.prototypesubType.prototype = Object.create(superType && superType.prototype, {constructor: { // 重写 constructorvalue: subType,enumerable: false,writable: true,configurable: true}});if (superType) {Object.setPrototypeOf? Object.setPrototypeOf(subType, superType): subType.__proto__ = superType;}
}

五.关于Object.prototype.__proto__已经弃用

后续可通过Object.getPrototypeOf(obj)来获取原型!
在这里插入图片描述

示例

let Circle = function () {};
let shape = {};
let circle = new Circle();// 设置该对象的原型链引用
// 过时且不推荐使用的。这里只是举个例子,尽量不要在生产环境中这样做。
shape.__proto__ = circle;// 判断该对象的原型链引用是否属于 circle
console.log(shape.__proto__ === circle); // true

相关文章:

原型、原型链、__proto__与prototype的区别、继承

一.什么是原型与原型链 根据MDN官方解释: JavaScript 常被描述为一种基于原型的语言——每个对象拥有一个原型对象[[Prototype]] ,对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类…...

前端 面经

1说一说cookie sessionStorage localStorage 区别?解题思路得分点 数据存储位置、生命周期、存储大小、写入方式、数据共享、发送请求时是否携带、应用场景 标准回答 Cookie、SessionStorage、 LocalStorage都是浏览器的本地存储。 它们的共同点:都是存储…...

[oeasy]python0080_设置RGB颜色_24bit_24位真彩色_颜色设置

RGB颜色 回忆上次内容 上次 首先了解了 索引颜色 \33[38;5;XXXm 设置 前景为索引色\33[48;5;XXXm 设置 背景为索引色 RGB每种颜色 可选0-5总共 6 级 想用 精确RGB值 真实地 大红色画个 大红桃心 ♥️ 有可能吗??🤔 rgb 模式 关于 RGB 模式…...

实战项目-用户评论数据情绪分析

目录1、基于词典的方法2、基于词袋或 Word2Vec 的方法2.1 词袋模型2.2 Word2Vec3、案例:用户评论情绪分析3.1 数据读取3.2 语料库分词处理3.3 Word2Vec 处理3.4 训练情绪分类模型3.5 对评论数据进行情绪判断目的:去判断一段文本、评论的情绪偏向在这里&a…...

day02 DOS(续)文本编辑快捷键 发展史

day02课堂笔记 1、常用的DOS命令(续) 1.1、del命令,删除一个或者多个文件 删除T1.class文件 C:\Users\Administrator>del T1.class 删除所有.class结尾的文件,支持模糊匹配 C:\Users\Administrator>del *.class T1.classT1…...

arm64与aarch64

结论: 目前arm64和aarch64概念已合并,新版64位arm程序统称aarch64. 问题引入: 存在部分机器,安装arm版本ss,会报错,提示 rootlocalhost ~]# rpm -ivh senseshiel50 59130arm64.rpm Verifying... ########…...

QString详解

QString存储16位Qchar(Unicode)字符串 QString使用隐式共享(copy-on-write)来提高性能。 什么是Unicode? unicode是一种国际标准,支持当今使用的大多数操作系统,他是US-ASCII和Latin-1的超集(与子集相同字符编码相同…...

SpringCloud微服务

一、微服务架构 1.1、单体应用架构 将项目所有模块(功能)打成jar或者war,然后部署一个进程 优点: 1:部署简单:由于是完整的结构体,可以直接部署在一个服务器上即可。 2:技术单一:项目不需要复杂的技术栈,往往一套熟悉的技术栈就可以完成开…...

Hive 连接及使用

1. 连接 有三种方式连接 hive: cli:直接输入 bin/hive 就可以进入 clihiveserver2、beelinewebui 1.1 hiveserver2/beeline 1、开启 hiveserver2 服务 // 前台运行,当 beeline 输入命令时,服务端会返回 OK [roothadoop1 bin]…...

android libavb深入解读

1、vbmeta结构解析 2、 libavb代码解读 代码地址https://cs.android.com/android/platform/superproject/+/master:external/avb/libavb/ 解析参考AVB源码学习(四):AVB2.0-libavb库介绍1_摸肚子的小胖子的博客-CSDN博客 这篇blog将会更加深入,掌握avb流程。 2.1、avb_slot_…...

【面试题】对闭包的理解?什么是闭包?

大厂面试题分享 面试题库后端面试题库 (面试必备) 推荐:★★★★★地址:前端面试题库闭包的背景由于js中只有两种作用域,全局作用域和函数作用域,而在开发场景下,将变量暴露在全局作用域下的时候…...

笔试题-2023-乐鑫-数字IC设计【纯净题目版】

回到首页:2023 数字IC设计秋招复盘——数十家公司笔试题、面试实录 推荐内容:数字IC设计学习比较实用的资料推荐 题目背景 笔试时间:2022.09.01应聘岗位:数字IC设计工程师笔试时长:60min笔试平台:nowcoder牛客网题目类型:单选题(2道)、不定项选择题(7题)、问答题(…...

antd日期组件时间范围动态跟随

这周遇到了一个很诡异但又很合理的需求。掉了一周头发,死了很多脑细胞终于上线了。必须总结一下,不然对不起自己哈哈哈。 一、需求描述 默认当前日期时间不可清空。 功能 默认时间如下: 目的:将时间改为 2014-08-01 ~ 2014-08…...

mysql一条sql语句的执行过程

sql的具体执行过程 客户端发送一条查询给服务器服务器下先检查查询缓存,如果命中了缓存,返回缓存中的结果否则就需要服务器端进行sql的解析、预处理,再由优化器生成对应的执行计划根据执行计划,调用存储引擎的api来执行查询将结果…...

SaaS是什么,和多租户有什么关系?

空间数据又称几何数据,用来表示物体的位置,形态,大小分布等各方面的信息,是对现实世界中存在的具有定位意义的事物和现象的定量描述。 多租户是SaaS领域特有的产物。 SaaS服务是部署在云上的,客户可以按需购买&#…...

C语言---字符串函数总结

🚀write in front🚀 📝个人主页:认真写博客的夏目浅石. 🎁欢迎各位→点赞👍 收藏⭐️ 留言📝 📣系列专栏:夏目的C语言宝藏 💬总结:希望你看完之…...

MySQL-表的基本操作

一、创建数据表创建数据表是指在已经创建好的数据库中建立新表。创建数据表的过程是规定数据列的属性的过程&#xff0c;同时也是实施数据完整性约束的过程。创建表之前应先使用语句{use 数据库名} 进入到指定的数据库&#xff0c;再执行表操作。创建表语法:CREATE TABLE <表…...

开篇之作—闲聊几句AUTOSAR

背景信息 步入职场已有些许年头,遇到过不少的人,经历过不算多的事情,也走过一些地方。现在坐下来想想,觉得一路走过总是行色匆匆,都来不及停下来驻足路边的风景,抑或是回头看看身后的精彩。 现在有些庆幸的是,加入了这个汽车这个行业,从事着汽车电子开发领域,也因此…...

02- 天池工业蒸汽量项目实战 (项目二)

忽略警告: warnings.filterwarnings("ignore") import warnings warnings.filterwarnings("ignore") 读取文件格式: pd.read_csv(train_data_file, sep\t) # 注意sep 是 , , 还是\ttrain_data.info() # 查看是否存在空数据及数据类型train_data.desc…...

LeetCode-111. 二叉树的最小深度

目录题目分析递归法题目来源111. 二叉树的最小深度题目分析 这道题目容易联想到104题的最大深度&#xff0c;把代码搬过来 class Solution {public int minDepth(TreeNode root) {return dfs(root);}public static int dfs(TreeNode root){if(root null){return 0;}int left…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

Java 8 Stream API 入门到实践详解

一、告别 for 循环&#xff01; 传统痛点&#xff1a; Java 8 之前&#xff0c;集合操作离不开冗长的 for 循环和匿名类。例如&#xff0c;过滤列表中的偶数&#xff1a; List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

使用 SymPy 进行向量和矩阵的高级操作

在科学计算和工程领域&#xff0c;向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能&#xff0c;能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作&#xff0c;并通过具体…...

中医有效性探讨

文章目录 西医是如何发展到以生物化学为药理基础的现代医学&#xff1f;传统医学奠基期&#xff08;远古 - 17 世纪&#xff09;近代医学转型期&#xff08;17 世纪 - 19 世纪末&#xff09;​现代医学成熟期&#xff08;20世纪至今&#xff09; 中医的源远流长和一脉相承远古至…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...