看完这篇文章,你应该懂什么叫继承了吧

栏目: JavaScript · 发布时间: 7年前

内容简介:说到继承呢?肯定有很多做java的朋友都觉得是一个比较简单的东西了。毕竟面向对象的三大特征就是:封装、继承和多态嘛。但是真正对于一个javascript开发人员来说,很多时候其实你使用了继承,但其实你不知道这叫继承。今天我就借这篇文章来谈一谈继承在前端的几种实现方式。但是原型继承有有有些缺点,来看下面一段代码:从上面的代码,我们可以清楚的发现:所有的实例都会公用一个原型链,如果一个实例中修改原型 那么所有实例的值都会被修改。

说到继承呢?肯定有很多做 java 的朋友都觉得是一个比较简单的东西了。毕竟面向对象的三大特征就是:封装、继承和多态嘛。但是真正对于一个javascript开发人员来说,很多时候其实你使用了继承,但其实你不知道这叫继承。今天我就借这篇文章来谈一谈继承在前端的几种实现方式。

一、 原型继承

function Animal(name = 'animal'){
	this.name = name
}
Animal.prototype.eat = function(food){
	console.log('dasdsa')
	return `${this.name} eat ${food}`;
}

function Dog(){
}
Dog.prototype = new Animal();

var instance = new Dog();
instance.name = 'dog';
console.log(instance.eat('bone'));
console.log(instance instanceof Dog); // true
console.log(instance instanceof Animal); // true
复制代码

但是原型继承有有有些缺点,来看下面一段代码:

function Animal(name = 'animal'){
	this.name = name
	this.skinColors = ['black','white']
}
Animal.prototype.eat = function(food){
	return `${this.name} eat ${food}`;
}

function Dog(){
}
Dog.prototype = new Animal();

var instance = new Dog();
instance.name = 'keji';
instance.skinColors.push('red');
console.log(instance.eat('bone'));
console.log(instance instanceof Dog); // true
console.log(instance instanceof Animal); // true

var instance1 = new Dog()
console.log(instance1.skinColors) // [ 'black', 'white', 'red' ]
复制代码

从上面的代码,我们可以清楚的发现:所有的实例都会公用一个原型链,如果一个实例中修改原型 那么所有实例的值都会被修改。

二、 构造函数继承

针对前面原型链继承可能会存在公用一个原型链的问题,那么我们可以给大家介绍一种方式:构造函数的继承。构造函数的继承相当于将父类复制给子类。

function Animal(name = 'animal'){
	this.name = name
	this.skinColors = ['black','white']
}
Animal.prototype.eat = function(food){
	return `${this.name} eat ${food}`;
}

function Dog(){
	Animal.call(this);
}

var instance = new Dog();
instance.name = 'keji';
instance.skinColors.push('red');
console.log(instance.eat('bone')); // TypeError: instance.eat is not a function
console.log(instance instanceof Dog); // true
console.log(instance instanceof Animal); // true

var instance1 = new Dog();
console.log(instance1.skinColors); // [ 'black', 'white' ]
复制代码

但是这种方法也有自己缺点:

  • 不能继承原型上面的属性和方法
  • 复制的处理,相当于在子类中实现了所有父类的方法,影响子类的性能。

三、 组合继承

原型链继承能继承父类原型链上的属性,但是可能会存在篡改的问题;而构造函数继承不会存在篡改的问题,但是不能继承原型上面的属性。那么我们是不是可以将两者进行结合呢?

function Animal(name = 'animal'){
	this.name = name
	this.skinColors = ['black','white']
}
Animal.prototype.eat = function(food){
	return `${this.name} eat ${food}`;
}

function Dog(){
	Animal.call(this);
}
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;


var instance = new Dog();
instance.name = 'keji';
instance.skinColors.push('red');
console.log(instance.eat('bone'));
console.log(instance.skinColors) // [ 'black', 'white', 'red' ]
console.log(instance instanceof Dog); // true
console.log(instance instanceof Animal); // true

var instance1 = new Dog()
console.log(instance1.skinColors) // [ 'black', 'white' ]
复制代码

这种方法呢?调用了两次父类的构造函数,有些许损耗性能,并且子类的构造函数的属性会和原型上面的属性相重合。(优先原用构造函数的属性)

四、 原型式继承

function object(obj){
  function F(){}
  F.prototype = obj;
  return new F();
}


let Programmer = {
	features:["tutou","jiaban","single"]
}

// 方式一:最原始的做法
var programmer1 = object(Programmer);
programmer1.features.push('meiqian');
console.log(programmer1.features); // [ 'tutou', 'jiaban', 'single', 'meiqian' ]
var programmer2 = object(Programmer);
console.log(programmer2.features); // [ 'tutou', 'jiaban', 'single', 'meiqian' ]

// 方式二 es中的Object.create
var programmer3 = Object.create(Programmer);
console.log(programmer3.features); // [ 'tutou', 'jiaban', 'single', 'meiqian' ]
复制代码

从上面的代码很明显的可以发现:和构造函数继承一样也存在被篡改的可能,并且也不能传递参数。

五、 寄生式继承

在原型式继承的基础上面增强了对象,并返回构造函数。

function pFactory(obj){
	let clone = Object.create(obj);
	clone.motto = function(){
		console.log('hardworking and not lazy!!')
	}
	return clone;
}

var programmer1 = new pFactory(Programmer);
console.log(programmer1.motto()); // hardworking and not lazy!!
console.log(programmer1.features); // [ 'tutou', 'jiaban', 'single' ]
复制代码

这种继承的方法同样和原型继承一样,存在被篡改的可能。

六、 寄生组合式继承

前面说了这么多,每种继承方式都有自己的优点和缺点,那么是不是可以将这些继承的方式做一个合并:以他之长补己之短呢?来看下面一段代码:

function Animal(name = 'animal'){
	this.name = name
	this.skinColors = ['black','white']
}
Animal.prototype.eat = function(food){
	return `${this.name} eat ${food}`;
}

function inheritPrototype(subType, superType){
  var prototype = Object.create(superType.prototype);
  prototype.constructor = subType; 
  subType.prototype = prototype;
}


function Dog(name,sound){
	Animal.call(this,name);
	this.sound = sound;
}

inheritPrototype(Dog,Animal);

Dog.prototype.getSound = function(){
	console.log(`${this.name} ${this.sound}`);
}

var instance = new Dog('keji','wangwangwang!!!');
instance.skinColors.push('red');
console.log(instance.eat('bone'));
console.log(instance.skinColors) // [ 'black', 'white', 'red' ]
console.log(instance instanceof Dog); // true
console.log(instance instanceof Animal); // true
console.log(instance.getSound()) // keji wangwangwang!!!

var instance1 = new Dog('haha','wangwang!!!')
console.log(instance1.skinColors) // [ 'black', 'white' ]
console.log(instance1.getSound()) // haha wangwang!!!
复制代码

这个例子的效率的体现在它只调用了一次父类的构造函数,这很大程度上面减少创建了不必要多余的属性。并且还能继承原型链上面的方法。这个方法是现在库的实现方法。

七、 es6的继承方法

class Animal {
	constructor(name){
		this.name = name;
	}

	get getName(){
		return this.animalName()
	}

	animalName(){
		return this.name;
	}

}

class Dog extends Animal{
	constructor(name,sound){
		super(name);
		this.sound = sound;
	}
	get animalFeature(){
		return `${this.getName} ${this.sound}`
	}
}

let dog = new Dog('keji','wangwangwang!');
console.log(dog.animalFeature); // keji wangwangwang!
复制代码

其实我们晓得,class语法也是由es5语法来写的,其继承的方法和寄生组合式继承的方法一样。关于es6的类,我在代码自检的时候遇到的两个重点,值得注意下的是:

  • 函数声明会提升,类声明不会。
  • ES5的继承实质上是先创建子类的实例对象,然后再将父类的方法添加到this上。但是es6是先创建父类的实例对象this,然后再用子类的构造函数修改this。

说在最后

好像什么都没写就差不多快12点了,最近在疯狂的复习。但是却发现越学东西越多,感觉有点学不完的意味在里面 外加上最近好像有点高考考砸之后的失眠综合症,搞的我整个人都不怎么舒服。明明高考都过去差不多6年了,还一直困扰着我,贼恐怖,算了 算了 先不写了 睡觉去了。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

How to Build a Billion Dollar App

How to Build a Billion Dollar App

George Berkowski / Little, Brown Book Group / 2015-4-1 / USD 24.95

Apps have changed the way we communicate, shop, play, interact and travel and their phenomenal popularity has presented possibly the biggest business opportunity in history. In How to Build a Billi......一起来看看 《How to Build a Billion Dollar App》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具