前端继承的几种方法

本文深入探讨JavaScript中的五种继承模式:原型链继承、借用构造函数、组合继承、寄生组合继承,对比各自的优缺点,帮助开发者理解并选择合适的继承方式。

原型链继承

function Person(){
   this.name = "hello",
   this.hobby = ['唱歌','踢球'];
}

function Child(){
}
//关键代码
Child.prototype = new Person();
Child.prototype.constructor = Child;
var child = new Child();
child.hobby .push('跑步');
var child2 = new Child();
console.log(child2.hobby ) //['唱歌','踢球','跑步']

总结:缺点不能传递参数,2,如果父类的属性是引用类型,子类实列修改了该属性,其他的子类实列会会共享该属性。

借用用构造函数

借用构造函数实现继承,也就是通过call或者apply方法调用父类构造函数,以实现继承。
//父类
function Person(name){
	this.name = name;
	this.hobby  = ['唱歌','踢球','跑步']
}
Person.prototype.eat = function(){
	console.log("好吃");
}
//子类
function Child(age,name){
	this.age = age;
	Person.call(this,name)
}
//实列
var child1 = new Child('11','wucr');
child1.push('学习')
console.log(child1.hobby )// ['唱歌','踢球','跑步','学习']
var child2 = new Child('11','wucr');
console.log(child2.hobby )// ['唱歌','踢球','跑步']

借用构造函数有缺点总结:
缺点:1,子类无法继承父类在原型链上的属性和方法。2,每个实例都拷贝一份,占用内存大,尤其是方法过多的时候。(函数复用又无从谈起了,本来我们用 prototype 就是解决复用问题的)
优点:解决了通过原型链继承子类对于父类引用类型属性的修改,导致其他子类实列共享了修改的问题

组合继承

组合继承(原型链继承+借用构造函数继承)由于这两种继承方式都存在各自的优缺点,从而将他们优点结合起来,通过原型继承父类原型上的属性和方法,通过构造函数的方法继承父类的属性
function Person(name){
	this.name = name;
	this.hobby  = ['唱歌','踢球','跑步']
}
Person.prototype.eat = function(){
	console.log("好吃");
}
//子类
function Child(age,name){
	this.age = age;
	Person.call(this,name) //借用构造函数
}
Child.prototype = new Person(); // 原型链
Child.prototype.constructor = Child;

缺点:组合继承是js最常用的继承模式,组合继承最大的问题就是无论在什么情况下,都会调用两次构造函数:一次是在创建子类型原型时,另一次是在子类构造函数内部。

寄生组合继承

寄生组合继承就是避免两次调用父类构造函数,通过赋值直接继承父类的原型
function Person(name){
	this.name = name;
	this.hobby  = ['唱歌','踢球','跑步']
}
Person.prototype.eat = function(){
	console.log("好吃");
}
//子类
function Child(age,name){
	this.age = age;
	Person.call(this,name) //借用构造函数
}
var proObj = Object.create(Person.prototype);
proObj.constructor = Child;
Child.prototype = proObj;
寄生组合继承是开发中比较常用的继承方法
### 继承的类型及实现方式 在前端开发中,继承是面向对象编程中的核心概念之一。通过继承,子类可以复用父类的属性和方法,同时可以根据需求进行扩展和修改。根据不同的实现方式,JavaScript 中的继承可以分为以下几种类型。 #### 1. 借用构造函数继承 这种继承方式主要通过在子类构造函数中调用父类构造函数来实现对父类属性的继承。它无法继承父类原型上的方法。 ```javascript function Parent(name) { this.name = name; } function Child(name, age) { Parent.call(this, name); // 借用构造函数继承 this.age = age; } ``` 这种方式的优点是能够实现对父类属性的继承,但缺点是不能复用原型链上的方法[^2]。 #### 2. 原型链继承 通过将子类的原型指向父类的一个实例,实现对父类属性和方法继承。然而,这种继承方式可能导致子类实例共享父类实例的属性值。 ```javascript function Parent() { this.name = "Parent"; } function Child() {} Child.prototype = new Parent(); // 原型链继承 ``` 优点是能够继承父类原型上的方法,但缺点是子类实例共享了父类的属性值,可能会导致数据污染[^2]。 #### 3. 组合继承 组合继承结合了借用构造函数和原型链继承的优点,既能够继承父类的属性,也能够继承父类原型上的方法。 ```javascript function Parent(name) { this.name = name; } Parent.prototype.sayName = function() { console.log(this.name); }; function Child(name, age) { Parent.call(this, name); // 借用构造函数继承属性 this.age = age; } Child.prototype = new Parent(); // 原型链继承方法 Child.prototype.constructor = Child; ``` 这种方法是较为通用的继承实现方式,但在调用父类构造函数时会执行两次,可能影响性能[^2]。 #### 4. 寄生式组合继承 寄生式组合继承是对组合继承的优化,通过减少调用父类构造函数的次数来提升性能。它使用 `Object.create()` 方法创建父类原型的副本,从而避免了直接调用父类构造函数。 ```javascript function Parent(name) { this.name = name; } Parent.prototype.sayName = function() { console.log(this.name); }; function Child(name, age) { Parent.call(this, name); // 借用构造函数继承属性 this.age = age; } Child.prototype = Object.create(Parent.prototype); // 寄生式继承 Child.prototype.constructor = Child; ``` 这种方式解决了组合继承中调用两次父类构造函数的问题,性能更优[^2]。 #### 5. 直接继承 prototype 通过将子类的原型直接指向父类的原型对象,实现继承。这种方式简单高效,但需要注意子类和父类的原型对象是共享的,修改子类原型可能会影响父类。 ```javascript function Parent() {} Parent.prototype.say = function() { console.log("Parent"); }; function Child() {} Child.prototype = Parent.prototype; // 直接继承 prototype ``` 这种方式的优点是实现简单,但缺点是子类和父类的原型对象共享,容易引发副作用[^2]。 #### 6. 改进直接继承 prototype 为了解决直接继承 `prototype` 的问题,可以通过创建父类原型的副本,再将其赋值给子类原型。这样可以避免共享问题。 ```javascript function Parent() {} Parent.prototype.say = function() { console.log("Parent"); }; function Child() {} Child.prototype = Object.create(Parent.prototype); // 改进直接继承 prototype Child.prototype.constructor = Child; ``` 这种方式避免了共享问题,是一种较为推荐的实现方式[^2]。 #### 7. ES6 的 `class` 和 `extends` ES6 引入了类和继承的语法糖,通过 `class` 和 `extends` 可以更直观地实现继承。 ```javascript class Parent { constructor(name) { this.name = name; } sayName() { console.log(this.name); } } class Child extends Parent { constructor(name, age) { super(name); // 调用父类构造函数 this.age = age; } } ``` 这种方式语法更简洁,可读性更高,是现代前端开发中推荐使用的继承方式[^1]。 ###
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值