手写js——继承
创始人
2024-04-21 18:40:52
0

原型链继承

所谓 函数 也就是 函数 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.prototypevar 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);

相关内容

热门资讯

安卓系统的如何测试软件,从入门... 你有没有想过,你的安卓手机里那些神奇的软件是怎么诞生的呢?它们可不是凭空出现的,而是经过一系列严格的...
小米8安卓系统版本,安卓系统版... 你有没有发现,手机更新换代的速度简直就像坐上了火箭呢?这不,小米8这款手机自从上市以来,就凭借着出色...
华为手机安卓系统7以上,创新体... 你有没有发现,最近华为手机越来越受欢迎了呢?尤其是那些搭载了安卓系统7.0及以上版本的机型,简直让人...
儿童英语免费安卓系统,儿童英语... 哇,亲爱的家长朋友们,你是否在为孩子的英语学习发愁呢?别担心,今天我要给你带来一个超级好消息——儿童...
ios系统切换安卓系统还原,还... 你有没有想过,有一天你的手机从iOS系统切换到了安卓系统,然后再从安卓系统回到iOS系统呢?这听起来...
灵焕3装安卓系统,引领智能新体... 你知道吗?最近手机圈里可是掀起了一股热潮,那就是灵焕3这款神器的安卓系统升级。没错,就是那个曾经以独...
安卓系统指南针软件,探索未知世... 手机里的指南针功能是不是让你在户外探险时倍感神奇?但你知道吗,安卓系统中的指南针软件可是大有学问呢!...
华为是不用安卓系统了吗,迈向自... 最近有个大新闻在科技圈里炸开了锅,那就是华为是不是不再使用安卓系统了?这可不是一个简单的问题,它涉及...
安卓系统热点开启失败,排查与解... 最近是不是你也遇到了安卓系统热点开启失败的小麻烦?别急,让我来给你详细说说这个让人头疼的问题,说不定...
小米max2系统安卓,安卓系统... 你有没有听说过小米Max2这款手机?它那超大的屏幕,简直就像是个移动的电脑屏幕,看视频、玩游戏,那叫...
电池健康怎么保持安卓系统,优化... 手机可是我们生活中不可或缺的好伙伴,而电池健康度就是它的生命力。你有没有发现,随着使用时间的增长,你...
安卓手机怎么调系统颜色,安卓手... 你有没有发现,你的安卓手机屏幕颜色突然变得不那么顺眼了?是不是也想给它换换“脸色”,让它看起来更有个...
安卓系统清粉哪个好,哪款清粉工... 手机用久了,是不是觉得卡得要命?别急,今天就来聊聊安卓系统清理垃圾哪个软件好。市面上清理工具那么多,...
华为被限制用安卓系统,挑战安卓... 你知道吗?最近科技圈可是炸开了锅!华为,这个我们耳熟能详的名字,竟然因为一些“小插曲”被限制了使用安...
安卓系统是不是外国,源自外国的... 你有没有想过,我们每天离不开的安卓系统,它是不是外国货呢?这个问题听起来可能有点奇怪,但确实很多人都...
安卓系统缺少文件下载,全面解析... 你有没有发现,用安卓手机的时候,有时候下载个文件真是让人头疼呢?别急,今天就来聊聊这个让人烦恼的小问...
kktv系统刷安卓系统怎么样,... 你有没有听说最近KKTV系统刷安卓系统的事情?这可是个热门话题呢!咱们一起来聊聊,看看这个新玩意儿到...
安卓系统连接电脑蓝牙,操作指南... 你有没有遇到过这种情况:手机里堆满了各种好用的应用,可就是想找个方便快捷的方式,把手机里的音乐、照片...
安卓车机11.0系统包,智能驾... 你有没有发现,最近你的安卓车机系统好像悄悄升级了呢?没错,就是那个安卓车机11.0系统包!这可不是一...
安卓系统最高到多少,从初代到最... 你有没有想过,你的安卓手机系统升级到哪一步了呢?是不是好奇安卓系统最高能到多少呢?别急,今天就来带你...