首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >js实现继承

js实现继承

作者头像
hss
发布于 2022-02-25 19:14:10
发布于 2022-02-25 19:14:10
7.1K0
举报
文章被收录于专栏:前端卡卡西前端卡卡西

js实现继承

经典继承(原型链)

  • 缺点:过多的继承了没用的属性
代码语言:javascript
复制
Grandfather.prototype.lastName = 'zhang'
function Grandfather() {
    this.money = 100
}
var grandfather = new Grandfather()
Father.prototype = grandfather
function Father() {
    this.work = 'code'
}
var father = new Father()
Son.prototype = father
function Son() {
    this.hobby = 'game'
}
var son = new Son()
console.log(son);

​ son只想要继承grandfather的lastName属性,但是由于原型链的关系,造成了son既会继承grandfather自神的东西,grandfather的原型的东西,father自身的东西和father原型上的东西,造成了不必要的继承

共享原型

本质:重写原型对象

优点:只会继承父的原型,不会继承父原本自带的属性或方法(只有调用new Father()才会继承自身的东西)

缺点:给本身的原型添加属性或方法时,会把继承的那个原型也修改了

代码语言:javascript
复制
Father.prototype.lastName = 'zhang'
function Father() {
    this.money = '100'
}
function Son() {
    this.hobby = 'game'
}
Son.prototype = Father.prototype
Son.prototype.food = 'fish'
var son = new Son()
var father = new Father()
console.log(Son.prototype)      // {lastName: "zhang", food: "fish", constructor: ƒ}
console.log(Father.prototype)   // {lastName: "zhang", food: "fish", constructor: ƒ}
console.log(son);               // Son {hobby: "game"}
console.log(father);            // Father {money: "100"}
console.log(son.money);         // undefined

借用构造函数(伪经典继承)

原理:在函数里面调用函数,约等于将父里面的代码复制粘贴到子里面,然后通过call将父的this改成子的this

缺点:

  1. 不能继承借用的构造函数的原型
  2. 每次调用子构造函数都要调用多一次借用的父构造函数,没有函数复用可言
代码语言:javascript
复制
Father.prototype.lastName = 'zhang'
function Father() {
    this.money = 100
}
function Son() {
    Father.call(this)
    this.hobby = 'game'
}
var son = new Son()
console.log(son);               // Son {money: 100, hobby: "game"}
console.log(son.lastName);      // undefined

组合继承

本质:重写原型对象

原理:借用构造函数+原型链

缺点:因为需要借用构造函数,还是没有函数复用

代码语言:javascript
复制
Father.prototype.lastName = 'zhang'
function Father() {
    this.money = 100
}
function Son() {
    Father.call(this)
    this.hobby = 'game'
}
Son.prototype = new Father()
var son = new Son()
console.log(son);               // Son {money: 100, hobby: "game"}
console.log(son.lastName);      // zhang

圣杯模式(寄生组合式继承)

雏形

本质:重写原型对象

优点:只会继承父的原型,不会继承父原本自带的属性或方法(只有调用new Father()才会继承自身的东西)

缺点:1,这样继承后即使修改了son的原型也不会修改father的原型,但会修改给father的实例;2,Son的原型指向了father实例,造成了Son的constructor缺失。

代码语言:javascript
复制
Father.prototype.lastName = 'zhang'
function Father() {
    this.money = '100'
}
function Son() {
    this.hobby = 'game'
}
var father = new Father()
Son.prototype = father
Son.prototype.food = 'fish'
var son = new Son()
console.log(Son.prototype)      // Father {money: "100", food: "fish"}   
console.log(Father.prototype)   // {lastName: "zhang", constructor: ƒ}
console.log(son.food);          // fish
console.log(father.food);       // fish
console.log(son.lastName);      // zhang

​ Son.prototype指向father实例,但是Son.prototype.food并不能改变father实例的prototype,因为想要改变prototype,必须通过他本身的原型去修改,如:Son.prototype.__proto__.food:'fish',通过Son.prototype.__proto__获取father的原型进行修改而Son.prototype.food,只是在改变father实例

改进

原理:使用一个F构造函数当中间层,F的原型继承父构造函数的原型,然后子的原型指向F的实例,重新给子的原型指定constructor

代码语言:javascript
复制
Father.prototype.lastName = "zhang"
function Father() {
    this.money = '100'
}
function Son() {
    this.hobby = 'game'
}
function F() {
}
F.prototype = Father.prototype
Son.prototype = new F()
Son.prototype.constructor = Son
Son.prototype.food = 'fish'
var son = new Son()
var father = new Father()
console.log(Son.prototype)      // Father {food: "fish", constructor: ƒ}
console.log(Father.prototype)   // {lastName: "zhang", constructor: ƒ}
console.log(son.food);          // fish
console.log(father.food);       // undefined
console.log(son.lastName);      // zhang

封装

手写版
代码语言:javascript
复制
function inherit(Target, Origin) {
    function F() { };
    F.prototype = Origin.prototype;
    Target.prototype = new F();
    Target.prototype.constuctor = Target;
    Target.prototype.super = Origin.prototype;   // 超类
}
YAHOO(YUI)版

其实就是利用闭包和立即执行函数

​ inherit右边的立即执行函数,定义了一个function F() {}这个构造函数(约等于一个私有化函数),然后返回了一个function,这个function里面保存着立即执行函数里面的F,形成闭包,因此返回的这个function可以访问这个F,而这个F只是作为中间层传递原型给目标而已,传递完之后F这个构造函数就没用了,而立即执行函数在执行完后就会销毁F,因此,高端操作(利用闭包延长F的生命周期,又利用立即执行函数将F销毁)。

代码语言:javascript
复制
var inherit = (function () {
    function F() { }
    return function (Target, Origin) {
        F.prototype = Origin.prototype;
        Target.prototype = new F();
        Target.prototype.constuctor = Target;
        Target.prototype.uber = Origin.prototype;   // 超类
    }
}())
用法
代码语言:javascript
复制
Father.prototype.lastName = 'zhang'
function Father() {
    this.money = '100'
}
function Son() {
    this.hobby = 'game'
}
inherit(Son, Father)
var son = new Son()
var father = new Father()
Son.prototype.grade = 6
console.log(son);               // Son {hobby: "game"}
console.log(father);            // Father {money: "100"}
console.log(Son.prototype);     // Father {uber: {…}, grade: 6, constuctor: ƒ}
console.log(Father.prototype);  // {lastName: "zhang", constructor: ƒ}
console.log(son.lastName);      // zhang
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/07/23 ,如有侵权请联系 cloudcommunity@tencent.com 删除
目录
  • js实现继承
    • 经典继承(原型链)
    • 共享原型
    • 借用构造函数(伪经典继承)
    • 组合继承
    • 圣杯模式(寄生组合式继承)
      • 雏形
      • 改进
      • 封装
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档