59、js实现继承的几种方式

发布时间:2023-05-07 18:30

目录

1、原型链继承:将父类的实例作为子类的原型

2、借用构造函数继承:复制父类的实例属性给子类

3、实例继承:为父类实例添加新特性,作为子类实例返回

4、组合继承(原型链继承+借用构造函数继承):可传参、继承原型

5、es6的extends


首先定义一个父类Animal:

//构造函数
function Animal(name) {
	this.name = name || \'Animal\';
	this.sleep = function() {
		console.log(this.name + \'正在睡觉!\');
	};
}
//原型上面的方法:
Animal.prototype.eat = function(food) {
	console.log(this.name + \'正在吃:\' + food);
}

1、原型链继承:将父类的实例作为子类的原型

关键语句:Dog.prototype = new Animal();

显著缺点:无法继承多个;

\"59、js实现继承的几种方式_第1张图片\"

\"59、js实现继承的几种方式_第2张图片\"

特点:

  1. 非常纯粹的继承关系,实例是子类的实例,也是父类的实例
  2. 父类新增原型方法/原型属性,子类都能访问的到
  3. 简单

缺点:

  1. 无法实现继承多个
  2. 来自原型对象的所有属性被所有实例共享
  3. 创建子类实例时,无法向父类构造函数传参(在子类中可通过this.name赋值,子类实例调用父类方法时,也可访问到)
  4. 为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放到构造器中。例:Dog.prototype.name = \'dog\';

2、借用构造函数继承:复制父类的实例属性给子类

核心:使用父类的构造函数增强子类实例,等于是复制父类的实例属性给子类没用到原型

关键语句:Animal.call(this)

显著缺点:只能继承父类的实例属性和方法,不能继承父类原型属性/方法。故只是子类的实例,不是父类的实例;

\"\"

\"59、js实现继承的几种方式_第3张图片\"

特点:

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

缺点:

  • 实例并不是父类的实例,只是子类的实例
  • 只能继承父类的实例属性和方法,不能继承原型属性/方法
  • 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能

3、实例继承:为父类实例添加新特性,作为子类实例返回

关键语句:var instance = new Animal();    return instance;

显著缺点:是父类的实例(因为通过new调用了父类),不是子类的实例

\"59、js实现继承的几种方式_第4张图片\"

\"59、js实现继承的几种方式_第5张图片\"

特点:

  • 不限制调用方式,不管是new子类(),还是子类(),返回的对象都具有相同的效果

缺点:

  • 实例是父类的实例,不是子类的实例
  • 不支持多继承

4、组合继承(原型链继承+借用构造函数继承):可传参、继承原型

核心:通过调用父类构造函数继承父类的属性可传参,然后将父类实例作为子类原型继承原型属性/方法。

关键语句:Animal.call(this); //构造函数

                    Cat.prototype = new Animal(); //原型链继承

显著缺点:会调用两次父类的构造函数

\"59、js实现继承的几种方式_第6张图片\"

\"59、js实现继承的几种方式_第7张图片\"

特点:

  • 即可以继承实例属性/方法,也可以继承原型属性/方法
  • 既是子类的实例,也是父类的实例
  • 不存在引用属性共享问题
  • 可传参
  • 函数可复用

缺点:

  • 调用了俩次父类的构造函数,生成了俩份实例(子类实例将子类原型上的那份屏蔽了)

5、es6的extends

\"59、js实现继承的几种方式_第8张图片\"

\"59、js实现继承的几种方式_第9张图片\"

注意:

  1. 子类必须在constructor方法中调用super方法。如果子类没有定义constructor方法,会被默认添加constructor方法以及其内部的super方法。
  2. 在子类的constructor方法中,只有调用super之后,才可以使用this关键字,否则会报错。
  3. super内部的this指的是子类的实例
  4. super作为对象时,在子类中指向父类的原型对象。即super=Parent.prototype。
     

6、寄生组合式继承

子类的原型 child.prototype 指向父类的原型 father.prototype;

子类原型的构造函数 child.prototype.constructor 指向子类本身 child;

关键语句:

inheritPrototype方法设置子类的原型,使其指向父类的原型,并且构造函数指向子类本身;

father.apply(this,[])  //父类构造函数

特点:

  1. 寄生组合式继承的高效体现在它只调用了一次Person构造函数
  2. 并且因此避免了在Pan.prototype上面创建不必要的、多余属性
  3. 原型链还能保持不变
  4. 还能正常使用instanceof和isPropertyOf()
  5. 开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。
//1. 实现子类继承父类(通用方法)。child类继承father类 。子类的原型指向父类的原型,子类的构造函数指向其本身
	function inheritPrototype(child,father){
		var prototype = Object.create(father.prototype); // 1)子类原型 指向父类的原型
		prototype.constructor = child; // 2) 子类原型的构造函数指向child类。
		child.prototype = prototype; // 3)设置子类的原型为prototy。
	}
 
	//2. 创建父类
	function father(name){
		this.faName = \'father\';
	}
	father.prototype.getfaName = function(){
		console.log(this.faName);
	}
 
	//3. 创建子类
	function child(args){
		this.chName = \'child\';
		father.apply(this,[]); //借用父类的构造函数,可访问父类本身的方法和属性
	}
	// 继承父类
	inheritPrototype(child,father);
	// 子类原型上添加方法
	child.prototype.getchName = function(){
		console.log(this.chName);
	}
 
	//4. 打印测试
	let c = new child();
	console.log(c.faName); //father
	c.getfaName(); //father
	console.log(child.prototype.isPrototypeOf(c)); //true。child的实例对象的原型是否是child.prototype
    console.log(c instanceof child) //true
    console.log(c instanceof father) //true

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号