手写js——继承

news2024/10/6 8:27:33

原型链继承

所谓 函数 也就是 函数 Father其本身,也叫作构造函数 ,当一个函数被创建的同时,也会为其创建一个 prototype 属性,而这个属性,就是用来指向 函数原型,的我们可以把 prototype 理解为 Father的一个属性,保存着函数原型的引用。

  • 当访问一个对象的属性(包括方法时),首先查找这个对象自身有没有该属性。  
  • 如果没有就查找它的原型(也就是 __proto__指向的 prototype 原型对象)。
  •  如果还没有就查找原型对象的原型(Object的原型对象)。依此类推一直找到为null为止。
  • __proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线。
     
//一、原型链继承
function Father(){
   
}
Father.prototype.name="father"
// Father.prototype.sex="man"
function Son(){
 
}
Son.prototype.name="son"
Son.prototype.sex="woman"
var f=new Father()
Son.prototype=new Father()
Son.prototype.constructor=f;
var s=new Son();
console.log(s.name,"=============>son's name") //undefined
console.log(s.sex)

运行上述代码 会发现 s.name 结果为undefined 原因是我们在后面重新 改变了 Father.prototype的指向  所以找不到之前定义的name,所以在原型链定义属性要在 继承之后定义属性

function Father(){
   
}
Father.prototype.name="father"
// Father.prototype.sex="man"
function Son(){
 
}

var f=new Father()
Son.prototype=new Father()
Son.prototype.constructor=f;
var s=new Son();
Son.prototype.name="son"
Son.prototype.sex="woman"
console.log(s.name,"=============>son's name") //undefined
console.log(s.sex)

 

 

优点:

父类方法可以复用

缺点 :

  • 父类的引用属性会被所有子类实例共享

  • 子类的构建实例不能像父类构造函数传参 

构造函数继承

 实现 new函数

当使用new关键字调用构造函数生成一个对象实例时,js做出的关键处理如下:

  • 1.创建一个新的对象,将构造函数内this指针指向新建对象。
  • 2.将新建对象的__proto__属性设置成构造函数的prototype属性,确保新建对象是构造函数实例。
  • 3.运行一遍构造函数,如果构造函数本身需要返回一个object或者array对象,则舍去新创建对象,返回构造函数需要返回的对象;否则返回新建对象

/**
 * @bug 这里假设new出来实例的都是object,不是array对象
 * @description 传入构造函数,以及构造函数参数,模拟构造函数返回一个新建实例
 * @param {function} constructor 需要传入的构造函数
 * @param {any} params 跟在constructor参数后面的所有参数,用来模拟传入constructor的参数
 * @returns 返回一个新的对象
*/
function newFn(constructor){
  var obj={}
  obj.__proto__=constructor.prototype
  var params=Array.prototype.splice.call(arguments,1);
  constructor.apply(obj,params);
  return obj
}

function Person(name,age){
  this.name=name;
  this.age=age
}
let Cat={
  name:"",
  age:""
}
let person=newFn(Person,"Florenza",20)
console.log(person)
console.log(person instanceof Person)
// console.log(cat)


基本思想

构造函数继承的基本思想就是利用call或者apply把父类中通过this指定的属性和方法复制(借用)到子类创建的实例中。因为this对象是在运行时基于函数的执行环境绑定的。在全局中,this等于window,而当函数被作为某个对象的方法调用时,this等于那个对象。call 、apply方法可以用来代替另一个对象调用一个方法。call、apply 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。
new对象的时候(注意,new操作符与直接调用是不同的,以函数的方式直接调用的时候,this指向window,new创建的时候,this指向创建的这个实例),创建了一个新的实例对象,并且执行子类里面的代码,而子类里面用父类.call改变this指向,也就是说把this指向改成了指向新的实例,所以就会把SuperType里面的this相关属性和方法赋值到新的实例上,而不是赋值到SupType上面。所有实例中就拥有了父类定义的这些this的属性和方法。 

//二 构造函数继承
function Animal(){
    this.sex="male"
}
function Cat(){
    Animal.call(this)
}
console.log(new Cat().sex)

 

 优点:和原型链继承完全反过来

  • 父类的引用属性不会被共享

  • 子类构建实例时可以向父类传递参数

缺点:父类的方法不能复用,子类实例的方法每次都是单独创建的。

组合式继承

基本思想

组合继承有时候也叫伪经典继承,指的是将原型链和借用构造函数技术组合到一块,从而发挥二者之长的一种继承模式,其背后的思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样既通过在原型上定义方法实现了函数复用,又能保证每个实例都有它的自己的属性。

// 组合式继承
console.log("=============组合式继承=============")
function Animal2(){
    this.name="animal"
    this.sex="male"
}

function Dog(){
    this.name="dog"
    Animal2.call(this);
}
Dog.prototype=new Animal2();
console.log(new Dog().sex,"dog sex")

优点:

  • 父类的方法可以被复用
  • 父类的引用属性不会被共享
  • 子类构建实例时可以向父类传递参数

缺点:

调用了两次父类的构造函数,第一次给子类的原型添加了父类的name, arr属性,第二次又给子类的构造函数添加了父类的name, arr属性,从而覆盖了子类原型中的同名参数。这种被覆盖的情况造成了性能上的浪费。

原型式继承

主要思想

原型式继承并没有使用严格意义上的构造函数,是通过借助原型基于已有的对象创建新对象,同时还不必创建自定义类型。使用原型式继承的主要思路:

核心:原型式继承的object方法本质上是对参数对象的一个浅复制

优点:

父类方法可以复用。

缺点:

  • 父类的引用属性会被所有子类实例共享

  • 子类构建实例时不能向父类传递参数

console.log("===========原型式继承===========")
var people={
    name:"peopel",
    friends:["tiger"]
}
function createObject(o){
function F(){}
F.prototype=o;
return new F();
}
let elephant=createObject(people);
elephant.friends.push("mouse")

console.log(elephant.name)
console.log(elephant.friends)

 ECMAScript5新增Object.create( )方法规范了原型式继承。该方法接收了两个参数:一个用作新对象原型的对象和(可选)一个为新对象定义额外属性的对象。在传入一个参数的情况下Object.create( )和object( )方法的行为相同。如果传入两个参数,则Object.create( )的第二个参数与Object.defineProperties( )方法的第二个参数的格式相同:每个属性都是通过自己的描述符定义的。

 寄生式继承

接上面原型式继承,只在原型继承方法后面进行方法增强

即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,后再像真的是它做了所有工作一样返回对象。

console.log("===========寄生式继承==========")
//原型式继承方法
var people2={
    name:"peopel2",
    friends:["tiger"]
}
function createObject(o){
function F(){}
    F.prototype=o;
    return new F();
}
function createAnother(original){ 
    var fn=createObject(original)
    fn.say=function(){
        console.log("another")
    }
    return fn
} 
var man=createAnother(people2)
man.say()

优缺点:

仅提供一种思路,没什么优点。

组合式寄生式继承

即使用 组合式继承( xxx.call的方式)也使用 原型式 继承

了解了组合继承和寄生继承之后就是寄生式组合继承了,它是通过借用构造函数来继承属性,通过原型链形式来继承方法,会解决2次调用父类函数以及复用率的问题。

console.log("============组合式寄生式继承===========")
function Animal3(){
    this.name="animal3"
    this.age=10;
    this.friends=["cat"]
}
Animal3.prototype.getSay=function(){
    console.log("animal-3")
}
function Pig(){
    Animal3.call(this)
}
function createObj(o){
    function fn(){}
    fn.prototype=o;
    return new fn();
}

function inhertCreate(parent,child){
    let parentProto=createObj(parent.prototype);
    parentProto.constructor=child;
    child.prototype=parentProto;
}
// 核心:因为是对父类原型的复制,所以不包含父类的构造函数,也就不会调用两次父类的构造函数造成浪费
inhertCreate(Animal3,Pig)
var pig=new Pig();
console.log(pig)
pig.getSay()

 完美方式实现

ES6继承

主要思想

核心: ES6继承的结果和寄生组合继承相似,本质上,ES6继承是一种语法糖。但是,寄生组合继承是先创建子类实例this对象,然后再对其增强;而ES6先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。

class A {}
 
class B extends A {
 
 constructor() {
 
   super();
 
 }
 
}
 
ES6实现继承的具体原理:
 
class A {
 
}
 
class B {
 
}
 
Object.setPrototypeOf = function (obj, proto) {
 
 obj.__proto__ = proto;
 
 return obj;
 
}
 
// B 的实例继承 A 的实例
Object.setPrototypeOf(B.prototype, A.prototype);
 
// B 继承 A 的静态属性
Object.setPrototypeOf(B, A);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/81493.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用 Numba 加速 Python 代码,变得像 C++ 一样快

1. 介绍 Numba 是 python 的即时(Just-in-time)编译器,即当你调用 python 函数时,你的全部或部分代码就会被转换为“即时”执行的机器码,它将以你的本地机器码速度运行!它由 Anaconda 公司赞助&#xff0c…

SpringMVC初配置解析?

在springMVC-servlet中 在web.xml中 SpringMVC常用注解 Controller 负责注册一个bean 到spring 上下文中 RequestMapping 注解为控制器指定可以处理哪些 URL 请求 RequestBody 该注解用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行…

CentOS7安装Cockpit网页版图像化服务管理工具

不经意间看到CentOS8说是默认集成了Cockpit——网页版图像化服务管理工具,出于为了更好的管理自己的服务器,于是参考一些资料在自己的服务器CentOS7上也安装了一个。 一、Cockpit是什么 github 地址: https://github.com/cockpit-project/c…

[附源码]Python计算机毕业设计大数据与智能工程系教师档案管理系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等…

基于node.js+vue的社区团购网站 毕业设计

在当今社会的高速发展过程中,产生的劳动力越来越大,提高人们的生活水平和质量,尤其计算机科技的进步,数据和信息以人兴化为本的目的,给人们提供优质的服务,其中网上购买团购商品尤其突出,使我们…

移植知识点整理(续,后期持续添加)

一&#xff1a; uboot源码移植准备工作 1.在家目录下创建一个<demo>文件夹 2.将en.SOURCES-stm32mp1-openstlinux-5.10-dunfell-mp1-21-11-17_tar_v3.1.0.xz文件夹拷贝到demo目录下 3.对en.SOURCES-stm32mp1-openstlinux-5.10-dunfell-mp1-21-11-17_tar_v3.1.0.xz进行解压…

RK3568平台开发系列讲解(安卓适配篇)获取 root 权限

🚀返回专栏总目录 文章目录 一、关闭 selinux二、注释用户组权限检测三、su 文件默认授予 root 权限沉淀、分享、成长,让自己和他人都能有所收获!😄 📢此部分可以参考瑞芯微官方文档,在源码“Android11/rk_android11.0_sdk/RKDocs/android/patches/root”目录下。 一…

太全了!学Java项目,这就够了

你是否为不知道怎么入手去看一个开源项目&#xff1f; 你是否想看别人的项目学习笔记&#xff1f; 你是否想跟着别人的项目搭建过程一步一步跟着做项目&#xff1f; 今天给大家介绍一个网站&#xff0c;为了让更多Java的开发者能更容易找到值得学习的开源项目&#xff0c;我…

微服务框架 SpringCloud微服务架构 微服务保护 32 隔离和降级 32.4 熔断降级

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 微服务保护 文章目录微服务框架微服务保护32 隔离和降级32.4 熔断降级32.4.1 熔断降级32 隔离和降级 32.4 熔断降级 32.4.1 熔断降级 熔断…

[附源码]Python计算机毕业设计宠物交易网站Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

springcloud03:Eureka和Ribbon

Eureka和RibbonEureka介绍三大角色Eureka详解Eureka注册中心创建(springcloud-eureka模块)服务注册-信息配置-自我保护机制(服务提供模块)CAP原则Ribbon&#xff1a;负载均衡及Ribbon服务消费方(客户端)集成RibbonEureka介绍 三大角色 Eureka Serrver:提供服务的注册与发现。z…

day18【代码随想录】用栈实现队列、用队列实现栈、有效的括号

文章目录前言一、用栈实现队列&#xff08;力扣232&#xff09;二、用队列实现栈&#xff08;力扣225&#xff09;三、有效的括号&#xff08;力扣20&#xff09;前言 用栈实现队列 用队列实现栈 有效的括号 一、用栈实现队列&#xff08;力扣232&#xff09; 请你仅使用两个…

SpringBoot2基础入门

SpringBoot2基础入门学习要求环境要求学习资料01、Spring与SpringBoot1、Spring能做什么1.1、Spring的能力1.2、Spring的生态1.3、Spring5重大升级1.3.1、响应式编程1.3.2、内部源码设计2、为什么用SpringBoot2.1、SpringBoot优点2.2、SpringBoot缺点3、时代背景3.1、微服务3.2…

学生HTML个人网页作业作品:基于web在线汽车网站的设计与实现 (宝马轿车介绍)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

代码随想录刷题记录 day41 单词拆分+背包总结

代码随想录刷题记录 day41 单词拆分背包总结 参考&#xff1a;代码随想录 139. 单词拆分 思想 dp[i] 字符串长度为i&#xff0c;若dp[i]true&#xff0c;表示可以拆分为一个或多个在字典中出现的单词 递推公式 ​ 如果dp[j]true&#xff0c;[j,i]这个区间的子串出现在字典…

[附源码]Python计算机毕业设计大学生兼职平台Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

[附源码]计算机毕业设计基于Java的失物招领平台Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

C++ 多态之虚继承

什么是虚继承 C支持多继承的形式&#xff0c;但若被继承的不同基类又同属与某一个接口类or基类的派生类&#xff0c;那么很容易产生经典的菱形继承问题&#xff0c;这样不可避免的带来了命名冲突&#xff0c;访问不明确的问题&#xff0c;如图所示&#xff1a; 虚继承解决的…

【目标感知:IVIF:轻量级架构】

SELAFUSE: SEARCH A LIGHTWEIGHT ARCHITECTURE FOR TARGET-AWARE INFRARED AND VISIBLE IMAGE FUSION &#xff08;SELAFUSE: 搜索轻量级架构以实现目标感知的红外和可见光图像融合&#xff09; 尽管深度学习技术最近在红外和可见光图像融合方面表现出出色的性能&#xff0c;…

如何使用DNS加速你的浏览器访问速度?

不知道大家有没有遇到过这种情况, 我们访问用浏览器网页无法正常显示, 但是我们使用的QQ却能正常的打开? 这是因为 : 我们在登录QQ的时候是直接访问的腾讯的服务器, 在下载好的QQ客户端已经帮你配置好了所有的IP, 所有没有域名解析的操作, 所以可以正常的登录 解决办法如下…