一入前端深似海,从此红尘是路人系列第一弹之浅析JavaScript继承

简介: 继承算是JavaScript中的一大难点也是必须掌握的知识点。接下来我会列举一些我们常见的继承并给出对应一些的code方便大家理解。

继承算是JavaScript中的一大难点也是必须掌握的知识点。接下来我会列举一些我们常见的继承并给出对应一些的code方便大家理解。

1.类式继承,既子类原型继承父类实例化。但是当我利用new关键字实例化子类的时候,当我改变子类继承到父类属性的时候,会污染到再次实例化的子类它所继承到的属性。具体如下


function SuperClass(){
	this.superValue = true;
	this.languages= ['JS','JAVA'];
}
SuperClass.prototype.getSuperValue = function(){
	return this.superValue;
}
function SubClass(){
	this.subValue = false;
}
SubClass.prototype = new SuperClass();
SubClass.prototype.getSubValue = function(){
	return this.subValue;
}
var sub = new SubClass();
console.log(sub.getSuperValue());
console.log(sub.getSubValue());
console.log(sub instanceof SuperClass); //true
console.log(sub instanceof SubClass);	//true
console.log(SubClass instanceof SuperClass); //false
console.log(SubClass.prototype instanceof SuperClass); //true
console.log(sub.languages) //['JS','JAVA']
sub.languages.push('HTML');
var sub1 = new SubClass();
console.log(sub1.languages); //['JS','JAVA','HTML']
2.构造函数继承,即在子类构造函数中利用call()更改作用域,将子类变量在父类中执行一遍,从而完成继承。该继承方式只能继承父类构造函数中的属性和方法,并不能直接继承到父类原型。


function SuperClass(id,books){
	this.id = id;
	this.books = ['JS','JAVA'];
}
SuperClass.prototype.showBooks = function(){
	return this.books;
}
function SubClass(id,books){
	SuperClass.call(this,id,books)
}
var sub = new SubClass();
sub.books.push('CSS');
console.log(sub.books); //['JS','JAVA','CSS']
var sub1 = new SubClass('superClass');
console.log(sub1.books); //['JS','JAVA']
console.log(sub.showBooks()); //Uncaught TypeError: sub.showBooks is not a function

3.组合继承,即将类式继承和构造函数继承进行功能的结合,形成一个更为优良的继承方式。该继承结合了类式继承和构造函数继承,即继承了父类原型,又继承了父类构造函数中的属性和方法。这样的好处就是在用new关键字实例化一个子类的时候改变该子类继承到的属性,不会影响下一个实例化的子类继承到的属性。但是该继承方式的缺点就是子类原型继承父类实例化的时候,也会跑一次父类的构造函数。

function SuperClass(name){
	this.name = name;
	this.books = ['JS','JAVA'];
}
SuperClass.prototype.getName = function(){
	return this.name;
}
function SubClass(name,time){
	SuperClass.call(this,name);
	this.time = time;
}
SubClass.prototype = new SuperClass('superClass');
SubClass.prototype.getTime = function(){
	return this.time;
}
var sub = new SubClass('superClass');
sub.books.push('CSS');
console.log(sub.books); //['JS','JAVA','CSS']
console.log(sub.getName()); //superClass
var sub1 = new SubClass('superClass');
console.log(sub1.books); //['JS','JAVA']
4.原型式继承,它是对类式继承的一个封装,在原型式继承中会声明一个过渡对象,为的就是创建要返回的新的实例化对象。这里由于F过渡类的构造函数没有内容,所以开销比较小,使用起来也比较方便。但还是有着类式继承一样的问题。

function inheritObject(o){
	//声明一个过渡函数
	function F(){}
	//过渡对象的原型继承父对象
	F.prototype = o;
	return new F();
}
var book = {
	name:'js book',
	alikeBook:['css book','html book']
}
var newBook = inheritObject(book);
newBook.name = 'ajax book';
newBook.alikeBook.push('xml book');
var otherBook = inheritObject(book);
otherBook.name = 'flash book';
otherBook.alikeBook.push('as book');
console.log(newBook.name); //ajax book
console.log(newBook.alikeBook); //['css book','html book','xml book','as book']
console.log(otherBook.name); //flash book
console.log(otherBook.alikeBook); //['css book','html book','xml book','as book']
console.log(book.name); //js book
console.log(book.alikeBook); //['css book','html book','xml book','as book']
5.寄生式继承,它是对原型继承的第二次封装,让新创建的对象不仅仅有父类中的属性和方法而且还可以添加新的属性和方法。

//声明基对象
function inheritObject(o){
	//声明一个过渡函数
	function F(){}
	//过渡对象的原型继承父对象
	F.prototype = o;
	return new F();
}
var book = {
	name:'js book',
	alikeBook:['css book','html book']
}
function createBook(obj){
	//通过原型继承方式创建对象
	var o = new inheritObject(obj);
	//拓展新对象
	o.getName = function(){
		console.log(this.name);
	};
	//返回拓展后的新对象
	return o;
}

6.寄生组合式继承,它将寄生式继承和构造函数继承进行结合,形成一个完美的继承方式。


/**
 * 寄生式继承 继承原型
 * 传递参数 subClass 子类
 * 传递参数 superClass 父类
 */
function inheritObject(o){
	//声明一个过渡函数
	function F(){}
	//过渡对象的原型继承父对象
	F.prototype = o;
	return new F();
}
function inheritPrototype(subClass,superClass){
	//复制一份父类的原型副本保存在变量
	var p = inheritObject(superClass.prototype);
	//修正因为重写子类原型导致子类的constructor指向父类
	p.constructor = subClass;
	//设置子类的原型
	subClass.prototype = p;
}
//定义父类
function SuperClass(name){
	this.name = name;
	this.colors = ['red','blue'];
}
//定义父类原型方法
SuperClass.prototype.getName = function(){
	return this.name;
}
//定义子类
function SubClass(name,time){
	//构造函数继承
	SuperClass.call(this,name);
	//子类新增属性
	this.time = time;
}
//寄生式继承父类原型
inheritPrototype(SubClass,SuperClass);
//子类新增原型方法
SubClass.prototype.getTime =function(){
	return this.time;
}
var test1 = new SubClass('js book',2014);
var test2 = new SubClass('csc book',2013);
test1.colors.push('black');
console.log(test1.colors); //['red','blue','black']
console.log(test2.colors); //['red','blue']
console.log(test2.getName());
console.log(test2.getTime());

至此,最终完美的寄生组合式继承便由此诞生了。

此篇文章只是我个人的一些见解,希望可以帮助到一些对于继承还比较模糊的小伙伴们。当然,如果有小伙伴觉着哪里有问题,欢迎指出,大家一起探讨交流。

原文发布时间为:2016年09月10日
原文作者: qiangdada 

本文来源:开源中国 如需转载请联系原作者









目录
相关文章
|
2天前
|
JavaScript 前端开发 C++
【Web 前端】JavaScript window.onload 事件和 jQuery ready 函数有何不同?
【5月更文挑战第2天】【Web 前端】JavaScript window.onload 事件和 jQuery ready 函数有何不同?
|
3天前
|
JavaScript 前端开发 开发者
【Web 前端】什么是JS变量提升?
【5月更文挑战第1天】【Web 前端】什么是JS变量提升?
【Web 前端】什么是JS变量提升?
|
5天前
|
缓存 前端开发 JavaScript
【JavaScript 技术专栏】JavaScript 前端路由实现原理
【4月更文挑战第30天】本文探讨了JavaScript前端路由在SPA中的重要性,阐述了其基本原理和实现方式,包括Hash路由和History路由。前端路由通过监听URL变化、匹配规则来动态切换内容,提升用户体验和交互性。同时,文章也提到了面临的SEO和页面缓存挑战,并通过电商应用案例分析实际应用。理解并掌握前端路由能助开发者打造更流畅的单页应用。
|
5天前
|
JavaScript 前端开发
JavaScript 继承的方式和优缺点
JavaScript 继承的方式和优缺点
|
5天前
|
前端开发 JavaScript 数据安全/隐私保护
前端javascript的DOM对象操作技巧,全场景解析(二)
前端javascript的DOM对象操作技巧,全场景解析(二)
|
5天前
|
移动开发 缓存 JavaScript
前端javascript的DOM对象操作技巧,全场景解析(一)
前端javascript的DOM对象操作技巧,全场景解析(一)
|
5天前
|
缓存 编解码 自然语言处理
前端javascript的BOM对象知识精讲
前端javascript的BOM对象知识精讲
|
5天前
|
JavaScript 前端开发 开发者
【Web 前端】JS模块化有哪些?
【4月更文挑战第22天】【Web 前端】JS模块化有哪些?
|
9月前
|
Web App开发 前端开发 JavaScript
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-fiber解决了什么问题
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-fiber解决了什么问题
98 0
|
9月前
|
前端开发 定位技术
前端学习笔记202305学习笔记第二十三天-地图单线程配置
前端学习笔记202305学习笔记第二十三天-地图单线程配置
66 0
前端学习笔记202305学习笔记第二十三天-地图单线程配置