原型、原型链、__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-表的基本操作
一、创建数据表创建数据表是指在已经创建好的数据库中建立新表。创建数据表的过程是规定数据列的属性的过程,同时也是实施数据完整性约束的过程。创建表之前应先使用语句{use 数据库名} 进入到指定的数据库,再执行表操作。创建表语法: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题的最大深度,把代码搬过来 class Solution {public int minDepth(TreeNode root) {return dfs(root);}public static int dfs(TreeNode root){if(root null){return 0;}int left…...
美国是如何对GEO进行监管的?
一、GEO投毒并不是中国独有 2026年央视“315”晚会首次把“GEO投毒”这一灰色产业链推到台前。所谓“投毒”,说白了,就是有人通过批量制造虚假信息、污染训练或检索数据,去干扰AI的推荐和回答结果,最后把一些虚假、低质甚至根本不…...
农业IoT部署卡在MQTT连接失败?Python异步通信优化全链路解析(含田间实测吞吐量对比数据)
第一章:农业IoT部署卡在MQTT连接失败?Python异步通信优化全链路解析(含田间实测吞吐量对比数据)在华北平原某智慧农场的边缘网关部署中,23台土壤温湿度传感器频繁出现MQTT连接超时与会话重置现象,平均重连耗…...
Python实战:5分钟搞定小红书自动点赞脚本(附完整代码)
Python实战:5分钟实现小红书自动化互动工具开发指南 在当今内容爆炸的时代,社交媒体运营已成为个人品牌和商业推广的重要阵地。小红书作为国内领先的生活方式分享平台,其互动数据直接影响内容曝光和账号权重。对于开发者而言,掌握…...
OpenOCD入门到精通:第23章 添加新的 JTAG 适配器驱动
第23章 添加新的 JTAG 适配器驱动 导读摘要:OpenOCD 支持 40 余种调试适配器,每种适配器背后都有一个遵循统一接口规范的驱动程序。本章从 adapter_driver 结构体出发,逐一解析其回调函数语义,介绍 libusb/HIDAPI 通信层封装,并通过一个完整的简易驱动实现示例,帮助读者掌…...
STC89C52单片机+槽型光耦,手把手教你DIY一个低成本电机转速测量仪
STC89C52单片机槽型光耦DIY电机转速测量仪实战指南 从零搭建低成本测速系统的完整方案 电机转速测量在工业控制、机器人开发、智能小车等领域都是基础但关键的环节。市面上专业测速仪动辄上千元的价格让许多电子爱好者望而却步。其实,利用手头常见的STC89C52单片机…...
别再手动同步了!利用STM32定时器主从模式与ITR触发,实现硬件级精准定时联动
嵌入式系统中的定时器协同:STM32主从模式与ITR触发的硬件级联动 在工业控制、电机驱动和精密测量等场景中,多个定时器的精确协同往往是系统可靠性的关键。想象一下,当你的电机控制PWM需要与电流采样ADC严格同步,或者多个通信接口必…...
PyTorch 2.8镜像多场景落地:在线教育平台个性化习题生成引擎部署
PyTorch 2.8镜像多场景落地:在线教育平台个性化习题生成引擎部署 1. 教育行业的AI转型机遇 在线教育行业正面临个性化学习的迫切需求。传统题库系统存在内容同质化、更新成本高、难以匹配学生个体差异等问题。基于PyTorch 2.8构建的个性化习题生成引擎,…...
Cherry Studio终极模型集成指南:支持DeepSeek-R1等主流LLM的桌面AI神器
Cherry Studio终极模型集成指南:支持DeepSeek-R1等主流LLM的桌面AI神器 【免费下载链接】cherry-studio 🍒 Cherry Studio is a desktop client that supports for multiple LLM providers. Support deepseek-r1 项目地址: https://gitcode.com/GitHub…...
SpringBoot+Vue社区老年人帮扶系统源码+论文
代码可以查看文章末尾⬇️联系方式获取,记得注明来意哦~🌹 分享万套开题报告任务书答辩PPT模板 作者完整代码目录供你选择: 《SpringBoot网站项目》1800套 《SSM网站项目》1500套 《小程序项目》1600套 《APP项目》1500套 《Python网站项目》…...
从555到正弦波:手把手教你用立创EDA仿真+打样一个2KHz波形发生器(附完整工程)
从555到正弦波:立创EDA全流程打造2KHz波形发生器实战指南 在电子设计领域,波形发生器是最基础却又最考验设计功底的经典项目之一。想象一下,当你亲手设计的电路板输出完美的正弦波时,那种成就感绝非购买现成模块可比。本文将带你用…...
