一入前端深似海,从此红尘是路人系列第一弹之浅析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 

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









目录
相关文章
|
1天前
|
移动开发 JavaScript 前端开发
【热门话题】Vue.js:现代前端开发的轻量级框架之旅
Vue.js,由尤雨溪于2014年创建,是一个轻量级的前端框架,因其简洁API、高效渲染和组件系统深受全球开发者喜爱。本文探讨Vue的核心理念、技术架构、开发实践及在现代Web开发中的应用。Vue遵循渐进式框架思想,提供声明式编程、组件化和响应式数据绑定。技术上,它采用双向数据绑定、虚拟DOM和生命周期钩子。开发实践中,Vue CLI和Vuex、Vue Router分别加速开发和管理状态、路由。Vue不仅适用于单页应用,还支持多页应用、移动开发和跨平台项目,拥有丰富的社区生态和插件。随着Vue 3的推出,Vue将持续创新并影响前端开发领域。
20 0
|
3天前
|
前端开发 JavaScript
前端 JS 经典:函数管道
前端 JS 经典:函数管道
5 0
|
3天前
|
前端开发 JavaScript
前端 JS 经典:数组去重万能方法
前端 JS 经典:数组去重万能方法
7 0
|
3天前
|
缓存 JavaScript 前端开发
前端 JS 经典:CommonJs 规范
前端 JS 经典:CommonJs 规范
9 0
|
3天前
|
JavaScript 前端开发
前端 JS 经典:原型和原型链
前端 JS 经典:原型和原型链
9 0
|
3天前
|
前端开发 JavaScript API
前端 JS 经典:Proxy 和 DefineProperty
前端 JS 经典:Proxy 和 DefineProperty
7 0
|
3天前
|
JavaScript 前端开发
前端 JS 经典:JS 基础类型和 typeof
前端 JS 经典:JS 基础类型和 typeof
6 0
|
3天前
|
前端开发 JavaScript
前端 JS 经典:双等号运算符的运算和转换规则
前端 JS 经典:双等号运算符的运算和转换规则
7 0
|
3天前
|
前端开发 JavaScript
前端 JS 经典:判断对象属性是否存在
前端 JS 经典:判断对象属性是否存在
7 0
|
3天前
|
前端开发 JavaScript 数据安全/隐私保护
前端 JS 经典:零宽字符
前端 JS 经典:零宽字符
6 0