11、原型链、原型继承和Class继承

article/2025/9/13 0:03:50

11.1 原型

每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,这个对象(函数.prototype)的用途是包含可以由特定类型的所有实例共享的属性和方法

11.2 原型链

基本思想就是利用原型让一个引用类型继承另一个引用类型的属性和方法

原型链的作用:如果在对象上没有找到需要的属性或方法引用,引擎就会继续在原型关联的对象上寻找。

原型链就是多个对象通过 __proto__ 的方式连接了起来。为什么 obj 可以访问到 valueOf 函数,就是因为 obj 通过原型链找到了 valueOf 函数

在这里插入图片描述
在这里插入图片描述

  • Object是所有对象的爸爸,所有对象都可以通过 __proto__找到它
  • Function是所有函数的爸爸,所有函数都可以通过 __proto__找到它
  • 函数的 prototype 是一个对象
  • 对象的__proto__属性指向原型,__proto__将对象和原型连接起来组成了原型链

扩展

1. js中__proto__和prototype的区别和关系?

  • __proto__是每个对象都有的一个属性,而prototype是函数才会有的属性。
  • __proto__指向的是当前对象的原型对象,而prototype指向的,是以当前函数作为构造函数构造出来的对象的原型对象。
  • prototype__proto__ 的关系就是:你的__proto__来自你构造函数的prototype

11.3 原型继承和Class继承

首先先来讲下 class,其实在 JS中并不存在类,class 只是语法糖,本质还是函数

class Person {}
Person instanceof Function // true

1. 原型链继承

优点:实现函数复用,简单
缺点: 1.子类实例共享属性,造成实例间的属性会相互影响
2. 创建子类实例的时候,不能向超类型的构造函数中传递参数

  function Super(){this.color=['red','yellow','black']}function Sub(){}//继承了color属性 Sub.prototype.color=['red','yellow','black']//原型链继承Sub.prototype=new Super()//创建实例 instance1.__proto__.colorconst instance1=new Sub()const instance2=new Sub()console.log(instance1.__proto__.color===instance2.__proto__.color) //true

2. 借用构造函数继承

优点:可以在构造函数中向超类型构造函数传递参数
缺点:不能函数复用,方法只能定义在构造函数中

//构造函数继承
function Parent(name) {this.name = namethis.rename = function () {this.name.push('xiuzhu')}
}function Child() {Parent.call(this, "chenyi")
}var child1 = new Child()
var child2 = new Child()
console.log(child.name) //chenyi
console.log(child1.rename === child2.rename) // false, 实例没有共享同一个方法

3. 组合继承

组合继承是最常用的继承方式

function Parent(value) {this.val = value
}
//原型式继承
Parent.prototype.getValue = function() {console.log(this.val)
}
//构造函数继承
function Child(value) {Parent.call(this, value)
}
//原型继承
Child.prototype = new Parent()const child = new Child(1)child.getValue() // 1
child instanceof Parent // true
  • 继承方式优点:实现了函数复用,且能在构造函数中传参,不会与父类引用属性共享,可以复用父类的函数
  • 缺点:会调用两次超类型的构造函数,一次在创建子类型原型的时候,另一次在子类型构造函数内部。就是在继承父类函数的时候调用了父类构造函数,导致子类的原型上多了不需要的父类属性,存在内存上的浪费

4. 原型式继承

  1. 引用类型值会共享,值类型不会共享
    因为在改变值类型时,相当于给自己添加了属性。
    当去修改引用类型的某个值时,是在修改__proto__中的对象。但如果直接给引用类型赋值,那也和值类型一样,是给自己增加了属性
 function object(o){function F(){}//F.prototype={name:'ccdida',friends:['shelly','Bob']}F.prototype=o// new F() //F是个构造函数,返回F的实例:1.this此时用不上 2.将实例的__proto__指向F.prototype.//即返回了一个实例,其__proto__指向{name:'ccdida',friends:['shelly','Bob']}return new F()}var person={name:'ccdida',friends:['shelly','Bob']}var person1=object(person)var person2=object(person)//object函数相当于实现了Object.Create的功能console.log(person1.__proto__===person) //true person2.friends.push('shlimy')console.log(person1.friends)// ["shelly", "Bob", "shlimy"]

5. 寄生继承

缺点:不能做到函数复用,引用类型数据依然共享
原型式继承:基于已有的对象(原型对象)创建新对象(实现Object.create())
寄生式继承:创建一个用于封装继承过程的函数(实现Object.create()),同时以某种方式增强对象(比如添加方法)

 var person={name:'ccdida',friends:['shelly','Bob']}function createAnother(original){//clone.__proto__===originalvar clone=Object.create(original)//增强对象,添加属于自己的方法clone.sayHi=function(){console.log('hi')}return clone}var person1=createAnother(person)var person2=createAnother(person)person1.friends.push('shmily')console.log(person2.friends)//["shelly", "Bob","shmily"]person1.sayHi() //hi

4. 寄生组合继承
引用类型最理想的继承范式

前面的组合继承有个缺点:每次创建实例时都会调用两次超类方法,一次是通过new设置原型的时候,另一次是用call执行的时候

function Parent(value) {this.val = value
}
//原型式继承
Parent.prototype.getValue = function() {console.log(this.val)
}
//构造函数继承
function Child(value) {Parent.call(this, value)
}
//寄生继承
//Object.create()是ES5规范化的原型式继承:一个是用作新对象原型的对象和
//(可选的)一个新对象定义额外属性的对象
// 如下是补充因为重写Parent原型而失去默认的constructor属性,最后将新创建的对象赋值给子类型的原型
Child.prototype = Object.create(Parent.prototype, {constructor: {value: Child,enumerable: false,writable: true,configurable: true}
})const child = new Child(1)child.getValue() // 1
child instanceof Parent // true
  • 思路:不需要为了指定子类型的原型而调用超类型的构造函数(我理解为就是不需要显示的new操作),通过上面的寄生式继承方式来继承超类型的原型即可。

3. Class 继承

在 ES6 中,我们可以使用 class 去实现继承,并且实现起来很简单

class Parent {constructor(value) {this.val = value}getValue() {console.log(this.val)}
}
class Child extends Parent {constructor(value) {super(value)this.val = value}
}
let child = new Child(1)
child.getValue() // 1
child instanceof Parent // true
  • class 实现继承的核心在于使用 extends 表明继承自哪个父类,并且在子类构造函数中必须调用 super,因为这段代码可以看成 Parent.call(this, value)

参考文献

JavaScript原型&原型链


http://chatgpt.dhexx.cn/article/edfdq45A.shtml

相关文章

原型链和原型继承

什么是原型链? 每一个对象都有自己的原型对象,而原型对象也属于对象也会有自己的原型对象,依次类推就会形成链式结构,然后就构成了原型链,所有对象的原型链最终都会指向object.prototype,而最终object.pro…

关于原型、原型链和原型继承的理解

# 个人理解 原型: prototype首先是只作用于函数的属性,无法直接用于对象或变量。 每个函数中都自带一个__proto__属性(可以存储继承对象中的prototype属性--- p.__proto__ Person.prototype)。 在实例化对象(构造函数)时,寻找某个属性(如dem…

js原型和原型链以及原型继承

目录 一、原型 二、原型链 三、原型链继承 一、原型 原型是Javascript中的继承的基础,JavaScript的继承主要依靠原型链来实现的。 原型 ​ 在JavaScript中,我们创建一个函数A(就是声明一个函数), 就会为该函数创建一个prototype属性。而且也会在内存…

原型、原型链和原型继承

原型继承 编程中对象继承,有类继承和原型继承: 类继承形式上就是,extends 关键字,继承之后,子类就会拥有父类的属性和方法,如下: // 以下是 ES6 class 语法,语法上同类继承一样&a…

【JS继承】JS继承之原型链继承

自我介绍:大家好,我是吉帅振的网络日志;微信公众号:吉帅振的网络日志;前端开发工程师,工作4年,去过上海、北京,经历创业公司,进过大厂,现在郑州敲代码。 JS继…

原型链以及继承的几种方式

原型链以及继承的几种方式 学习原型链前需要了解原型链继承的几种方式 学习原型链前需要了解 只要创建一个新函数,就会根据特定的规则为该函数创建一个 prototype 属性,这个属性是一个指针,指向一个对象。这个对象的用途是包含可以由特定类型…

深入JS原型、原型链和继承

文章目录 一、原型的理解1.对象的原型2.函数的原型3.constructor 二、原型链1.概念和理解2.原型链中最顶层的原型 三、继承1.原型链继承:2.借用构造函数继承: 一、原型的理解 1.对象的原型 JavaScript当中每个对象都有一个特殊的内置属性[[prototype]]…

原型链与继承

目录 原型链 继承 Javascript为什么没有方法签名? 原型链继承 构造函数继承 组合继承 原型式继承 寄生继承 寄生组合继承 原型链 原型链是一种原型对象和实例对象的关系,通过属性__proto__进行联系。 继承 继承是一种允许我们在已有的类的基…

JS原型链和继承

JS原型链和继承 认识对象的原型 [[Get]]:JS的存取描述符——get方法,在获取对象属性时会自动调用 JavaScript当中每个对象都有一个特殊的内置属性[[prototype]],这个特殊的属性指向另外一个对象 [[prototype]]指向的对象: 当我…

JS原型链继承

再讲述JS原型链继承之前,我希望大家能够先理解 《函数,函数原型和函数实例之间的关系》,这样有助于大家理解JS原型链继承的原理,下面先看一张图吧,咱们看图说话: 如果大家看完了 《函数,函数原型和函数实…

原型链和继承的六种实现方式

一省:HTML 12. img标签的alt和title有什么不同? alt: 当图片加载不出来的时候,就会在图片未显示的地方出现一段 alt 设置的属性内容。浏览器的搜索引擎可以通过 alt 属性的文字描述来获取图片。 title: title是鼠…

原型,原型链,原型的继承

原型的作用? 1.节省内存空间 2.实现数据共享(继承) 什么是原型? 任何一个函数都有propotype属性,它本身是一个对象,我们称之为原型 构造函数,实例化对象与原型之间的关系? 1.任何一个函数都有prototype属性,它本身是一个对象,我们称之为原型 2.构造函数也是函数,也都…

JS原型、原型链和7种继承方法【白话文讲解】

前言 在学习JS原型、原型链和继承之前,我们必须先弄懂三个W,也就是我们常说的“学习三问” 学习三问: 1.它是什么?(What) 2. 为什么用它?(Why) 3. 什么时候用它&#xff…

原型链与常用继承方法

原型链:当访问一个对象的属性时,如果该对象内部不存在这个属性,就会去该对象的__proto__ 上(也就是它构造函数的prototype)查找 。该构造函数的prototype上也有一个自己的__proto__ 属性,然后继续向上查找,…

如何用原型链的方式实现一个 JS 继承?

大家好,我是前端西瓜哥。今天讲一道经典的原型链面试题。 原型链是什么? JavaScript 中,每当创建一个对象,都会给这个对象提供一个内置对象 [[Prototype]] 。这个对象就是原型对象,[[Prototype]] 的层层嵌套就形成了…

JS学习笔记 原型链和利用原型实现继承

原型链 原型链是一种关系,实例对象和原型对象之间的关系,关系是通过原型(__proto__)来联系的 实例对象中有__proto__,是对象,叫原型,不是标准的属性,浏览器使用,并且有的游览器不支持构造函数中有prototype属性,也是对象,叫原型 注意 原型中的方法是可…

Arduino基本知识(marlin固件配置)

初识arduino,根据mega2560(某宝可以买到)官网的100个管脚具体控制一句传输进行操作。 https://www.arduino.cc/en/Hacking/PinMapping2560 其管脚图如上所示。 首先在官网下载arduino的配套软件 https://www.arduino.cc/ 对于编程&#xf…

3D打印机硬件驱动-马林固件最新版本2.0.X中文注释(3)marlin 2.0.9.2 截至发稿时间2021年12月16日

/** * Marlin 3D Printer Firmware 头描述详见其他两个文件头描述 * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is…

Marlin固件配置

文档来源自http://www.geek-workshop.com/thread-33314-1-1.html 1、基本配置基本配置是可选的,主要是给你的固件起个名字,如果你的配置很牛,让大家知道你是谁。据说这个在启动的时候会显示在显示屏中,应为我没有显示屏,所以无法验证。这个修改也很简单,通过搜索找到“S…

MKS MONSTER8 V1.0使用说明书(基于Marlin 2.0.X固件配置Voron 2.4)

广州谦辉信息科技有限公司 (基于Marlin 2.0.x 固件配置 Voron 2.4) 创客基地QQ群:489095605 232237692 邮箱:Huangkaidamakerbase.com.cn 主板购买链接:https://item.taobao.com/item.htm?spma1z10.5-c-s.w4002-23356668283.43.7eec55caLT…