首页 > 其他分享 >实现js继承的几种方式以及他们的优缺点

实现js继承的几种方式以及他们的优缺点

时间:2023-03-04 11:23:07浏览次数:51  
标签:function 构造函数 console name 继承 优缺点 几种 js log

7.实现继承的几种方式以及他们的优缺点

①类式继承(构造函数)

 var father = function() {
   this.age = 52;
   this.say = function() {
     alert('hello i am '+ this.name ' and i am '+this.age + 'years old');
  }
 }
 
 var child = function() {
   this.name = 'bill';
   father.call(this);
 }
 
 var man = new child();
 man.say();

特点就是创建子类实例时,可以向父类传递参数,可以实现多继承(call多个父类对象)

缺点:

  • 实例并不是父类的实例,只是子类的实例

  • 只能继承父类的实例属性和方法,不能继承原型属性/方法

  • 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能

②组合式继承(伪经典继承)

原型链继承经典继承 组合。使用原型链继承方式实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又保证每个实例都有各自的属性。

 SuperType.prototype.greet = function() {
     return 'hello~,' + this.card.name;
 }
 •
 function SuperType(gender) {
     this.card = {
         name: '佩奇',
         age: 20,
         gender: gender
    }
 }
 ​

优点如上

不足:无论在什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部

③原型式继承

两种方法:

一、借用构造函数(本质上就是做了一次浅复制)

借用构造函数,在一个函数内部创建一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回这个临时类型的一个新实例。

二、使用Object.create() ES5通过增加Object.create()方法,将原型式继承的概念规范化了

 // 借用构造函数
 function helperFun(targetObj) {
     function newFun() {}
     newFun.prototype = targetObj;
     return new newFun();
 }
 •
 let myObj = {
     username: 'dog',
     age: 14,
     other: {
         hobby: 'reading',
         taste: 'sore'
    }
 }
 •
 console.log(myObj);
 let newObj = helperFun(myObj)
 newObj.username = 'cat';
 newObj.other.hobby = 'sleeping';
 console.log(newObj);
 ​
 --------------------------------------------------------
 // Object.create()
 let presentIbj = {
     username: '熊大',
     sex: 'male',
     age: 19,
     greet() {
         console.log('name is ' + this.username);
    }
 }
 •
 let newObj1 = Object.create(presentIbj);
 let newObj2 = Object.create(presentIbj);
 newObj1.username = '熊二';
 console.log(newObj1);
 console.log(newObj2);
 ​

④寄生式继承

寄生式继承就是创建一个仅用于封装继承过程的函数,该函数在内部以某种方式(使用原型式继承对一个目标对象进行浅复制,增强这个浅复制的能力)来增强对象,最后就好像像真的是它做了所有工作一样返回对象。引用类型的属性始终会被继承和共享。

/ 寄生式继承
function helperFun(targetObj) {
    function newFun() {};
    newFun.prototype = targetObj;
    return new newFun();
}
​
function packInherit(originObj) {
    let evalObj = helperFun(originObj);
    evalObj.greet = function() {
        console.log('hello~,' + this.name);
    };
    return evalObj;
}
​
let initObj = {
    name: '虹猫',
    like: ['reading', 'running'],
    age: 20
}
​
let newObj1 = packInherit(initObj);
console.log(newObj1); //[ 'reading', 'running', '蓝兔' ]
newObj1.like.push("蓝兔");
console.log(newObj1.like); //[ 'reading', 'running', '蓝兔' ]
newObj1.greet(); //hello~,虹猫
​
let newObj2 = packInherit(initObj);
newObj2.name = '蓝兔';
console.log(newObj2); //{ greet: [Function (anonymous)], name: '蓝兔' }
newObj2.greet(); //hello~,蓝兔
console.log(newObj2.like); //[ 'reading', 'running', '蓝兔' ]

优点就是:上手简单,无需单独创建构造函数。

缺点就是:函数复用率降低。

⑤寄生组合式继承

寄生组合继承是为降低父类构造函数的开销。通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。

// 寄生组合式
Super.prototype.say = function() {
    console.log(this.name);
}
function Super(name) {
    this.name = name,
    this.colors = ['red', 'blue', 'green']
}
function Son(name, age) {
    this.age = age;
    Super.call(this, name)
}
​
var another = Object.create(Super.prototype);
another.constructor = Son;
var another = Object.assign(Son.prototype(), Super.prototype())
// Son.prototype = another;
var instance1 = new Son('duck', 19)
instance1.
instance1.colors.push('pink')
var instance2 = new Son('cat', 18)

优点就是:只调用一次父构造函数,并且避免了在子原型上添加不必要,多余的属性。与此同时,原型链还能保持不变

缺点就是:代码太复杂

⑥class语法继承

// class继承
class Parent {
    constructor(name, gender) {
        this.name = name;
        this.gender = gender;
        this.greet = function() {
            console.log('greet');
        };
    }
    speak() {
        console.log("parent speak")
    }
​
    static speak() {
        console.log("static speak")
    }
}
​
//class 子类 extends 父类
class Son extends Parent {
    //在子类的构造方法中调用父类的构造方法
    constructor(name, gender, hobby) {
        super(name, gender);
        this.hobby = hobby;
    }
    //子类中声明的方法名和父类中的方法名相同时,子类中的方法将覆盖继承于父类的方法
    speak() {
        console.log("Son speak");
    }
}
const grandson = new Son('lucky', 'male', 'reading');
console.log(grandson.name, grandson.gender, grandson.hobby); //lucky male reading
grandson.greet(); //greet
grandson.speak(); //Son speak
Son.speak(); //static speak

 

标签:function,构造函数,console,name,继承,优缺点,几种,js,log
From: https://www.cnblogs.com/alwaysrun/p/17177913.html

相关文章

  • JS 概念、历史、发展和Js简介
    一、JS简介JavaScript(简称“JS”)是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。虽然它是作为开发Web页面的脚本语言而出名,但是它也被用到了很多非浏览器环境......
  • js 复制内容到剪切板
    项目介绍基于ThinkPHP6.0和layui的快速开发的后台管理系统。支持php8.0版本技术交流QQ群:533738074 加群请备注来源:如gitee、github、官网等。......
  • mockjs_axios_vue_learn_2023-03-03 23:33:34
    mockjsvuelearn/Users/song/Downloads/vue3_demo_mockjs-master/__mock_learn/mock_learn/index.html<!DOCTYPEhtml><htmllang="en"><head><metacharset="......
  • C#获取串口的几种方式
    摘要使用C#获取串口最简单的方式就是通过SerialPort对象了,但有时并不能满足需求,比如有些串口是通过驱动模拟的,那这种可能就获取不到了。示例代码这里简单演示几种常用的......
  • JS文件的几种格式之间的区别
    今天在修改公司ui组件库的时候,接触到npmrunlib,发现打包后文件有几种格式的文件。.common.js.common.js.map.umd.js.umd.js.map.umd.min.js.umd.min.js.map几种不......
  • JS 扩展构造树形结构数据方法遇到的奇怪bug,object键值赋值失败
    原方法:/***构造树型结构数据*@param{*}data数据源*@param{*}idid字段默认'id'*@param{*}parentId父节点字段默认'parentId'*@param{*}chil......
  • [前端] html和原生js实现鼠标拖动和触摸拖动以及点击后跟随鼠标移动
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>悬浮窗拖动点击事件</title><style>div{width:100px;......
  • FastJson JdbcRowSetImpl
    Java安全之FastJsonJdbcRowSetImpl链分析利用限制RMI利用的JDK版本≤JDK6u132、7u122、8u113LADP利用JDK版本≤6u211、7u201、8u191因为主要是FastJson,所以就不......
  • Apache设置反向代理解决js跨域问题
    这是一个很简单的方案,通过启用Apache反向代理解决js跨域问题为什么要这么做?在现在的开发过程中大家会遇到这样一个问题:后端代码写好之后,前端的小伙伴需要将后端代码部署......
  • Three.js实现高程数据加载
    通过加载高程数据(dem),显示地形高低起伏,达到良好的立体展示效果;Three.js能够通过设置一系列坐标点的高度,构建成面的形式,显示高程数据。实现方式:使用Three.js的PlaneGeometry进......