美文网首页
JavaScript的继承

JavaScript的继承

作者: 依然还是或者其他 | 来源:发表于2020-07-23 23:32 被阅读0次

前言

忘了整理的理一理。

ES5继承

先不涉及ES6的继承,后面会涉及。
这里主要是ES5的继承:

  • 原型链继承
  • 构造函数继承
  • 组合继承
  • 原型式继承
  • 寄生式继承
  • 寄生组合式继承
/**
 * 原型链继承
 */
console.log("----------------------------------原型链继承")
 const Man=function(){
     this.name="dad";
     this.sex='man';
     Man.prototype.say=function(){
         console.log("I am ",this.name);
     }
 }
 const pInstance=new Man();
 console.log(pInstance.constructor===Man); //true
 pInstance.say() //I am data

 const Child=function(){
     this.name="child";

 }
 Child.prototype=new Man();
 const cInstance=new Child();
 console.log(cInstance instanceof Man ) //true
 console.log(cInstance.constructor===pInstance.constructor) //true
 console.log(cInstance.constructor===Child) //false
 console.log("child:",cInstance.name) //child

原型链继承的一些问题:
1.因为继承是通过实例替换原型来到达的,那么实例原型的上的属性会被所以子类的实例所共享。
2.子类实例创建时,不能向父构造函数传递参数,因为会存在构造函数需要初始化参数的情况

/**
 * 构造函数继承
 */
console.log("----------------------------------构造函数继承")
const Man1=function(age){
    this.name="dad";
    this.sex='man';
    this.age=age;
}

const Child1=function(){
    Man1.call(this,11);
}
const cInstance1=new Child1();

console.log(cInstance1 instanceof Man1) //false
console.log(cInstance1)

构造函数继承的缺点
1.只能继承父类构造函数的属性,即父类原型的方法,子类也是无法调用的
2.无法实现构造函数的复用。因为1的原因,即方法需要在构造函数内生成,那么实例化每个函数都是独立的,即达不到复用的效果

/**
 * 组合继承 = 原型链继承+构造函数继承
 */
console.log("----------------------------------组合继承")
const Man2=function(){
    this.name="dad";
    this.sex='man';
}

const Child2=function(){
    
    Man2.call(this);
}
Child2.prototype=new Man2();
const cInstance2=new Child2();

console.log(cInstance2 instanceof Man2) //true
console.log(cInstance2.constructor===Child2)  //false
Child2.prototype.constructor=Child2;
console.log(cInstance2.constructor===Child2) //true

组合继承的缺点:
1.调用了两次构造函数,原型属性上会有重复的可能,即声明了多余的属性

/**
* 原型继承
*/
console.log("----------------------------------原型继承")
function createObj(obj){
    function O(){

    }
    O.prototype=obj;
    return new O();
}
const Man3=function(){
    this.name="dad";
    this.sex='man';
}
const mInstance3=new Man3();
const cInstance3=createObj(mInstance3);
console.log(cInstance3 instanceof Man3) //true
//所有的实例都会继承原型上的属性, 
//所有子类属性都是实例生成后添加的,无法复用

/**
 * 寄生继承
 */
console.log("----------------------------------寄生继承")

const Man4=function(){
    this.name="dad";
    this.sex='man';
}
const mIntance4=new Man4();

const createChild=function(obj){

    const childInstance=createObj(obj);
    // childInstance.name='child'
    childInstance.say=function(){
        console.log("I am",childInstance.name);
    }
    return childInstance;
}

const cIntance4=createChild(mIntance4);
cIntance4.say()

//无法复用,同构造函数继承

/**
 * 寄生组合继承
 */
console.log("----------------------------------寄生组合继承")

const Man5=function(){
    this.name="dad";
    this.sex='man';
}


const Child5=function(){
    Man5.call(this);
    this.sex="woman";
    this.age=11;
}
const ex=function(child,parent){
    const proto=Object.create(parent.prototype);
    // const proto=createObj(parent.prototype)
    proto.constructor=child;
    child.prototype=proto;
    
}
ex(Child5,Man5);

const cInstance5=new Child5();
console.log(cInstance5)
console.log(cInstance5 instanceof Man5); //true

//通过寄生的方式来解决组合继承中两次构造函数调用的问题


ES6继承

ES6的继承原理跟ES5的寄生组合继承有相似的地方。

class Parent {
  constructor(a){
    this.filed1 = a;
  }
  filed2 = 2;
  func1 = function(){}
}
class Child extends Parent {
    constructor(a,b) {
      super(a);
      this.filed3 = b;
    }
  
  filed4 = 1;
  func2 = function(){}
}


//babel 转换后

function _classCallCheck(instance,parent){ //es6class类的调用需要使用new的
 //instanceOf判断一个实例是否属于某种类型,也可以用来判断原型链
  if(!(instance instanceOf parent)){ 
     new TypeError("Cannot call a class as a function");
  }
}

var parent=function parent(a){ //可见class类的底层还是构造函数
   //_classCallCheck方法判断当前函数调用前是否有new关键字
    _classCallCheck(this,Parent); //this指向new出来的空对象
    this.filed1=a;
    this.filed2 = 2;
    this.func1 = function(){}
}
var Child = function (_Parent) {
  _inherits(Child, _Parent); //子类继承父类的proptype

  function Child(a, b) { //闭包保存父类的引用,在闭包中做子类的引用
    _classCallCheck(this, Child);//判断当前函数是否是使用new关键字调用

    //Child.__proto__ || Object.getPrototypeOf(Child)实际上是父构造函数(_inherits最后的操作),
   //然后通过call将其调用方改为当前this,并传递参数
    var _this = _possibleConstructorReturn(this, 
                (Child.__proto__ || Object.getPrototypeOf(Child)).call(this, a));

    _this.filed4 = 1;

    _this.func2 = function () {};

    _this.filed3 = b;
    return _this;
  }
  return Child;
}(Parent);

function _inherits(sub,parent){
    //当parent不为函数时必须为空,或者是当parent不为空时必须为函数,否则类型错误
    if(typeOf parent!=="function" && parent!==null){
        throw new TypeError(
          "Super expression must either be null or a function,not " + typeof superClass
       );
    }
    sub.prototype=Object.Create(parent&&parent.prototype,{//寄生组合继承
        constructor:{ value: sub, enumerable: false, writable: true, configurable: true }       
    })
    if(parent){
        Object.setPrototypeOf ? Object.setPrototypeOf(sub,parent):sub.__proto__ =parent
    }
}

function _possibleConstructorReturn(self, call) {
  if (!self) {//校验this是否被初始化
    throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
  }
  return call && (typeof call === "object" || typeof call === "function") ? call : self;
}

参考:

《JavaScript高级程序设计》
javascript中的六种继承方式
深入JavaScript继承原理
es6 class类继承实现原理

相关文章

  • 函数的原型对象

    什么是原型? 原型是Javascript中的继承的继承,JavaScript的继承就是基于原型的继承。 函数的原型...

  • 前端面试题目(二)

    javascript对象的几种创建方式 javascript继承的6种方法 详情:[JavaScript继承方式详...

  • 一文带你彻底理解 JavaScript 原型对象

    一、什么是原型 原型是Javascript中的继承的基础,JavaScript的继承就是基于原型的继承。 1.1 ...

  • 005|JavaScript ES6新特性之Classes

    在过去,需要像 053|JavaScript 继承详解 那样实现继承。JavaScript这种继承实现方式与其它面...

  • Web前端经典面试试题及答案2

    javascript面向对象中继承实现? 面向对象的基本特征有:封闭、继承、多态。在JavaScript中实现继承...

  • javascript代码积累

    一、javascript实现继承 1.基于原型链实现继承 2.基于属性和方法复制实现继承 二、javascript...

  • Javascript原型和原型链

    JavaScript在ES6之前没有类似class,extend的继承机制,JavaScript的继承主要是通过原...

  • 理解 JavaScript 中的原型链

    JavaScript 作为一门面对对象语言,但是却不支持接口继承,只支持实现继承。JavaScript 中实现继承...

  • Javascript 的继承

    这就实现了继承,ninja 里面有 dance 方法。

  • JavaScript的继承

    方法1:通过原型链 这种模式的问题是Dog的所有实例共享同一个Animal实例,一旦在dog1种修改Animal属...

网友评论

      本文标题:JavaScript的继承

      本文链接:https://www.haomeiwen.com/subject/pwxqfctx.html