js中的继承详解

JavaScript中的继承与原型链详解 同理,原型对象也是一个对象,它也有自己的原型对象,因此也可以继承它的原型对象的属性。这样的实现避免了引用类型的属性被所有实例共享的问题,在父类实例创建时还可以自定义地传参,缺点是方法都是在构造函数中定义,每次创建实例都会重新赋值一遍方法,即使方法的引用是一致的。在访问一个对象的时候,JavaScript 引擎会执行一个搜索过程,如果在对象实例上发现该属性,该属性值就会被使用,如果没有发现则搜索其原型对象。这就是原型继承链:对象继承其原型对象,而原型对象继承它的原型对象,以此类推。 阅读详情

js中的继承

假设我们有一个Animal类,我们想构造Cat类,Cat类可以继承Animal类的属性和方法。以这个场景为列,我来讲一讲我所理解的js的继承。

  1. 构造继承
function Animal(name){
  this.name = name;
  this.age = 15;
}

function Cat(name){
  Animal.call(this, name);
  this.catName = 'cat';
}

let o1 = new Cat('test1');
console.log(o1);
//Cat {name: "test1", age: 15, catName: "cat"}

这就是构造继承,在子类的构造函数中,调用父类的构造函数,这样父类构造函数中的属性就出现在了子类的构造函数中。
缺点:子类无法继承父类原型上的方法。

  Animal.prototype.say = function(){
     console.log(this.name)
  }
  o1.say;//undefined
  1. 原型继承
  function Cat2(name){
    this.catName = name;
  }
  Cat2.prototype = new Animal();
  let o2 = new Cat2('test2');
  console.log(o2);
  // Cat2 {catName: "test2"}
  o2.name;//undefined
  o2.age;//15
  o2.say;
  //ƒ (){
  //  console.log(this.name)
  //}

这种方法的缺点是无法进行父类传参初始化属性的继承,而且继承的父类的属性是所有子类共享的new Animal()这个对象实例上的属性,这就会导致如果更改了该对象实例的属性,那么这个影响就是所有子类实例共享的。
我们对父类做出如下更改

  function Animal(name){
    this.name = name;
    this.age = 15;
    this.friend = [1,2,3];
  }

  function Cat21(name){
    this.catName = name;
  }

  Cat21.prototype = new Animal();
  
  let o3 = new Cat21('o3');
  let o4 = new Cat21('o4');
  console.log('o3.age',o3.age);
  console.log('o4.age',o4.age);
  console.log('o3.friend',o3.friend);
  console.log('o4.friend',o4.friend);
  
  //更改数组friend
  o3.friend.push(4);
  console.log('o3.friend',o3.friend);
  console.log('o4.friend',o4.friend);
  
  //更改属性age
  o3.age = 19;
  console.log('o3.age', o3.age);
  console.log('o4.age', o4.age);

输出如下

    o3.age 15
    o4.age 15
    o3.friend (3) [1, 2, 3]
    o4.friend (3) [1, 2, 3]
    o3.friend (4) [1, 2, 3, 4]
    o4.friend (4) [1, 2, 3, 4]
    o3.age 19
    o4.age 15

我们可以发现更改friend时,这个更改在子类实例上都发生了改变,而更改age时,只在更改的实例上发生了变化。
我们来看看o3和o4
avatar
可以发现o3上的age属性是直接在实例上的,而o3和o4的实例本身都是没有friend属性的。
这是为什么呢?
这是因为在查找对象的属性和方法时,是沿着原型链进行查找的,而你更改属性时,如果这个属性不是一个引用类型,是会直接为实例对象本身添加一个相应的属性,如果是引用类型,是会改变所引用对象指向的内容的。 而原型链上的方法,是等同于非引用类型的属性的。
因此,如果我们想要修改age,让所有实例共享修改后的结果,我们可以这么修改
o3.__proto__.age = 99;
当然,这个前提是子类实例上还没有新增age属性。

  1. 构造 + 原型继承
     function Animal(name){
       this.name = name;
       this.age = 15;
       this.friend = [1,2,3];
     }
    
     Animal.prototype.say = function(){
         console.log(this.name);
     }
     function Cat3(name){
       Animal.call(this, name);
       this.catName = 'test3';
     }
     Cat3.prototype = new Animal();
    
     let o31 = new Cat3('o31');
     let o32 = new Cat3('o32');
    
     console.log('o31', o31);
     console.log('o32', o32);
     console.log('o31.friend', o31.friend);
     console.log('o32.friend', o32.friend);
    
     o31.friend.push(4);
     console.log('o31.friend', o31.friend);
     console.log('o32.friend', o32.friend);
    
     o31.say();
    

得到的输出如下:
avatar

可以发现父类的属性和方法子类实例都可以继承,但是还是有一个问题,那就是父类的构造函数多执行了一次,而这个多余的操作是不必要的。

  1. 原型+构造+优化1
    function Cat4(name){
      Animal.call(this, name);
      this.catName = name;
    }
    
    Cat4.prototype = Object.create(Animal.prototype);
    
     let o41 = new Cat4('o41');
     let o42 = new Cat4('o42');
    
     console.log('o41', o41);
     console.log('o42', o42);
     console.log('o41.friend', o41.friend);
     console.log('o42.friend', o42.friend);
    
     o41.friend.push(4);
     console.log('o41.friend', o41.friend);
     console.log('o42.friend', o42.friend);
    
     o41.say();
    

如此,我们就少进行了一个父类构造函数的执行,但是这还是有问题的

  o41 instanceof Cat4; //true
  o41 instanceof Animal; //true
  o41.constructor;//
  //ƒ Animal(name){
  //  this.name = name;
  //  this.age = 15;
  //  this.friend = [1,2,3];
  //}

也就是无法通过instanceof来确认实例对象是由父类构造还是子类构造。

  1. 原型+构造函数+优化2
    由于instanceof的本质就是在原型链上进行constructor属性的查找 ,我们可以做如下优化
 function Cat5(name){
   Animal.call(this, name);
   this.catName = name;
 }

  Cat5.prototype = Object.create(Animal.prototype);
  Cat5.prototype.constructor = Cat5;

  let o51 = new Cat5('o51');
  o51.constructor;
  //ƒ Cat5(name){
  //Animal.call(this, name);
  //this.catName = name;
  //}

以上是个人总结的继承相关的知识点,欢迎老铁们在评论区进行补充。

OASIS协议标准文档的解读_第一部分 OASIS标准协议的文档的解读。完整原协议的中文翻译和解读。 阅读详情

相关推荐

电流互感器的使用分析

有关电流互感器使用的注意事项,回头再看,耳目一新。

qq_46757048的博客 2万+

JS中的八种继承方法

详细讲解js中的八种继承方法,原型链继承、构造函数继承(经典继承)、组合面试、原型式继承、Object.create()、寄生式继承、寄生组合式继承、ES6类继承

weixin_70134200的博客 6646

windows11系统封装教程

1、 现在电脑品牌各式各样,小白对电脑软件的安装存在较大的难题,今天笔者针对以上的问题做如下教程:windows11系统封装教程方式为视频方式。

cyz141001的博客 5883

Js实现继承的6种方式

Js实现继承的6种方式: 1.原型链继承 2.借用构造函数继承 3.组合继承(经典继承) 4.原型式继承 方法一: 方法二:Object.create() 5.寄生式继承 6.寄生组合式继承 7.ES6、Class实现继承

wuliyouMaozhi的博客 2万+

解决VMware与Hyper-V/Device Guard冲突的实用指南

本文详细解析了VMware与Hyper-V/Device Guard冲突的根源,并提供了三种实用的解决方案:彻底关闭相关功能、通过启动配置实现选择性引导,以及使用VMware Workstation Pro的Hyper-V兼容模式。指南包含清晰的诊断步骤、操作命令和避坑建议,帮助用户根据自身需求灵活选择,实现虚拟化环境的稳定运行或高效共存。

weixin_29306317的博客 685

ROS中costmap_converter插件的配置与使用

在学习TEB算法的过程中,作者提供了一个插件用于转换代价地图,原始的代价地图是由栅格地图中单元格组成,用于表示障碍物,但单元格占用的计算资源较大,故采用插件将单元格转换成点,线,多边形表示。 插件激活 rospack plugins --attrib=plugin costmap_converter 配置cfg文件 在导航配置文件下,新建costmap_converter_params.yaml #######################################################

weixin_42621524的博客 5905

【笔记】JS实现继承的几种方式

JS实现继承的几种方式

weixin_44755080的博客 2689

管道机器人手臂机械结构设计cad【8张】+三维图+设计说明书+绛重

履带式管道机器人适用于各种管道环境,包括直管道、弯曲管道、水平管道、垂直管道等,其灵活性和适应性使得它可以应对不同形状和尺寸的管道,完成全面的检测和维护工作。管道机器人研究具有重要的现实意义和深远的社会影响,通过提高工作效率、降低人员风险、提升服务质量、节约成本资源和促进科技创新等方面的作用,为现代工程技术领域的发展和进步做出了积极的贡献。管道机器人是一种能够在管道内部执行各种任务的智能机器人,而管道机器人的机械臂对于管道机器人在管道内执行任务的灵活性、稳定性和效率至关重要。

kejigongjiang的博客 944

js的六种继承方式

1、原型链继承 核心: 将父类的实例作为子类的原型 特点: 1.非常纯粹的继承关系,实例是子类的实例,也是父类的实例 2.父类新增原型方法/原型属性,子类都能访问到 3.简单,易于实现缺点: 1.要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放到构造器中 2.无法实现多继承 3.来自原型对象的所有属性被所有实例共享(来自原型对象的引用属性是所有实例共享的) 4.创建子类实例时,无法向父类构造函数传参2、构造函数继承(借助 call) 核心:使用父类的构造函数来增强子类实例

weixin_41759744的博客 7748

S7-200 SMART PLC 数字量阀门控制功能块(FB)汇总

S7-200 SMART PLC功能块的各种写法可以查看专栏的其它文章,链接地址如下:S7-200 SMART PLC 子程序功能块(阀门控制)_RXXW_Dor的博客-优快云博客_plc控制阀门开关程序由于S7-200 SMARTPLC的子程序种种功能、容量限制,有时想实现多次调用的子程序可能并不是太容易,这篇博客还是给出一些推荐写法,供大家参看。

RXXW_Dor的博客 4002

沁恒CH32V30X学习笔记02--GPIO的使用教程及2次封装驱动

刚复位后,GPIO 口运行在初始状态,这时大多数 IO 口都是运行在状态所有的 GPIO 口都可以被配置外部中断输入通道,但一个外部中断输入通道最多只能映射到一个GPIO 引脚上,且外部中断通道的序号必须和 GPIO 端口的位号一致,,两方都是一对一的关系。复用功能。

Car12 707

JS的六种继承方式

最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。

小王的技术库 2118

Python进阶005:修改Jupyter Notebook的工作路径

1、Jupyter Notebook简介 2、修改Jupyter Notebook的工作路径 如下三个步骤: 一、安装notebook 在CMD命令行中输入: pip install notebook 二、启动notebook jupyter notebook 启动后发现是在你的用户目录下,如下图所示,但是该目录下有很多的其他文件或文件夹,因此我想把这个环境切换到我单门创建的一个文件夹中。 三、创建notebook的配置文件 在CMD命令行中执行: jupyter notebook --genera

若北辰 1387

js(javascript)实现继承的6种方式以及优缺点详解

js继承的6种方式 想要继承,就必须要提供个父类(继承谁,提供继承的属性)      一、原型链继承      重点:让新实例的原型等于父类的实例。     特点:1、实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。(新实例不会继承父类实例的属性!)     缺点:1、新实例无法向父类构造函数传参。        2、继承单一。        3、所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)      二、

m0_53592673的博客 2205

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

php中 继承中的概念,JavaScript_JavaScript中的继承方式详解,js继承的概念 js里常用的如下 - phpStudy...

JavaScript中的继承方式详解js继承的概念js里常用的如下两种继承方式:原型链继承(对象间的继承)类式继承(构造函数间的继承)由于js不像java那样是真正面向对象的语言,js是基于对象的,它没有类的概念。所以,要想实现继承,可以用js的原型prototype机制或者用apply和call方法去实现在面向对象的语言中,我们使用类来创建一个自定义对象。然而js中所有事物都是对象,那么用什么办...

weixin_39636696的博客 131

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

javascript中的继承详解

1 原型链继承 父类的实例作为子类的原型 function Woman(){ } Woman.prototype= new People(); Woman.prototype.name = 'haixia'; let womanObj = new Woman(); 优点:简单易于实现,父类的新增的实例与属性子类都能访问 缺点:可以在子类中增加实例属性,如果要新增加原型属性和方法需要在new 父类构造函数的后面 无法实现多继承 创建子类实例时,不能向父类构造函数中传参数 2.借用构造函数继承(伪造对象、

FengYang_的博客 197

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

JavaScript中继承方式详解

博文中介绍了JavaScript中实现继承的几种方式,详细介绍了其中的原型链、借用构造函数、组合继承以及原型式继承。

诗渊的博客 4960

JS继承详解

JS继承的几种方式,通过自己的理解解释几种继承方式的特点。

cxd_dxc的博客 3262

详解js继承

详解js继承 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录详解js继承前言一、预备知识1.构造函数的属性2.什么是原型对象3.原型对象的作用二、五种js继承方式方式1、原型链继承方式2、借用构造函数方式3、组合继承总结 前言 最近在复习准备面试题,这里记录一下关于js继承。 一、预备知识 1.构造函数的属性 function A(name){ this.name = name; //实例基本属性(该属性强调私有 不共享) this.arr = [1]; //实例引用属

yan的秘密基地 1666

JavaScript 继承方式详解

JavaScript提供了多种继承方式:1)原型链继承简单但共享引用属性;2)构造函数继承可传参但无法继承原型方法;3)组合继承结合两者优势;4)原型式继承基于现有对象;5)寄生式继承扩展原型式方法;6)寄生组合式继承是最理想的实现方式;7)ES6的class继承语法更清晰。推荐使用寄生组合式继承或ES6 class继承,它们既高效又避免了常见缺陷,是JavaScript面向对象编程的最佳实践。

qq_46032105的博客 1479

JavaScript:继承详解

继承 概念解析 继承的方式 继承的意义

KaiSarH 559

【JavaScript】寄生组合继承详解

寄生组合继承是一种改进版的组合继承,它通过解决了Parent构造函数调用两次的问题,使得 JavaScript 继承更加高效。尽管 ES6 的class语法在现代开发中更常见,但理解寄生组合继承的原理有助于深入掌握 JavaScript 的继承机制。

lph159的博客 1234

javascript中的继承详解:

1 原型链继承 父类的实例作为子类的原型 function Woman(){ } Woman.prototype= new People(); Woman.prototype.name = 'haixia'; let womanObj = new Woman(); 优点:简单易于实现,父类的新增的实例与属性子类都能访问 缺点:可以在子类中增加实例属性,如果要新增加原型属性和方法需要在new 父类构造函数的后面 无法实现多继承 创建子类实例时,不能向父类构造函数中传参数 2.借用构造函数继承(伪造对象、经

weixin_46174785的博客 196

【JavaScript】继承的实现方式详解

继承方式主要特点优点缺点原型链继承让子类prototype指向父类实例方法共享共享引用属性构造函数继承使用call调用父类解决共享问题,可传参方法无法复用组合继承构造函数 + 原型链解决共享问题调用两次父类构造函数寄生组合继承最优 ES5 方案解决所有问题代码略复杂ES6class继承最现代化方案语法简洁,推荐使用仅限 ES6+在现代 JavaScript 开发中,建议优先使用 ES6class继承,但在需要兼容旧浏览器时,可以使用寄生组合继承。

lph159的博客 2172

JavaScript继承方式详解

转自:http://segmentfault.com/a/1190000002440502 js继承的概念 js里常用的如下两种继承方式: 原型链继承(对象间的继承) 类式继承(构造函数间的继承) 由于js不像java那样是真正面向对象的语言,js是基于对象的,它没有类的概念。所以,要想实现继承,可以用js的原型prototype机制或者用apply和call方法去实现 ...

banfu7150的博客 95

JavaScript继承详解

http://www.cnblogs.com/sanshi/archive/2009/07/08/1519036.html  一、sanshi   javascript 继承系列:1、   JavaScript继承详解(一)    http://www.cnblogs.com/sanshi/archive/2009/07/08/1519036.html 2、JavaScript

livening的专栏 449
上一篇: new操作符的实现原理
下一篇: setTimeout与循环闭包
izwell
博客等级 码龄14年 16粉丝 88原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值