javaScript几种继承方案的实现
方案一: 原型链继承
让子构造函数的原型指向父构造函数的实例 优点:子实例可以继承父构造函数原型身上的属性和方法
缺点:1. 无法在创建子实例时给父构造函数传递参数
缺点:2. 所有子实例共用父实例的引用类型数据,如本例中son更改了hobbies daughter也受影响
function Parent() {
this.name = 'zhangsan',
this.hobbies = ['跑步','打球']
}
Parent.prototype.sayName = function() {
console.log(this.name);
}
function Child(age) {
this.age = age
}
Child.prototype = new Parent()
// TEST:创建子构造函数实例son、daughter
let son = new Child(8)
let daughter = new Child(6)
son.hobbies.push('打游戏')
console.log('son :>> ', son);
console.log('daughter :>> ', daughter);
方案二:借用构造函数继承
在子类构造函数中通过call/apply方法调用父类构造函数
优点:可以在子类构造函数中向父类构造函数传递参数、父类构造函数身上的引用类型属性会分别添加到子类实例身上,改变不会互相影响
缺点:不能继承父类构造函数原型上的属性和方法
function Parent(name, hobbies) {
this.name = name,
this.hobbies = hobbies
}
Parent.prototype.sayName = function() {
console.log(this.name);
}
function Child(age, ...args) {
Parent.apply(this, args)
this.age = age
}
let son = new Child(8, 'zhangsan',['跑步','打球'])
let daughter = new Child(6, 'zhangsi', ['跑步', '唱歌'])
son.hobbies.push('打游戏')
console.log('son :>> ', son);
console.log('daughter :>> ', daughter);
方案三: 组合继承
结合原型链式继承和借用构造函数继承的优点
优点:既可以在子类构造函数中给父类传参,又能继承父类构造函数原型上的属性和方法
缺点:父类构造函数被调用了两次
function Parent(name, hobbies) {
this.name = name,
this.hobbies = hobbies
}
Parent.prototype.sayName = function() {
console.log(this.name);
}
function Child(age, ...args) {
Parent.apply(this, args)
this.age = age
}
// 原型链继承
Child.prototype = new Parent()
Child.prototype.constructor = Child
let son = new Child(8,'zhangsan',['跑步','打球'])
let daughter = new Child(6,'zhangsi', ['跑步', '唱歌'])
son.hobbies.push('打游戏')
console.log('son :>> ', son);
console.log('daughter :>> ', daughter);
方案四:原型式继承
以一个已有的对象为原型创建新的实例
优点:可以很方便的继承一个已有对象的属性和方法
缺点:引用类型的属性会被所有新实例共用,互相操作会受影响
let parent = {
surname: 'zhang',
hobbies: ['跑步','打球'],
sayName: function() {
console.log(this.surname);
}
}
let son = Object.create(parent)
let daughter = Object.create(parent)
son.hobbies.push('打游戏')
console.log('son :>> ', son.hobbies);
console.log('daughter :>> ', daughter.hobbies);
方案五:寄生式继承
在原型式继承的基础上拓展新实例的属性和方法
优点:拓展了新实例的属性和方法
缺点:同原型式继承
function parasInherit(pObj) {
let newObj = Object.create(pObj)
newObj.sayHello = function() {
console.log('Hello');
}
return newObj
}
let parent = {
surname: 'zhang',
hobbies: ['跑步','打球'],
sayName: function() {
console.log(this.surname);
}
}
let son = parasInherit(parent)
son.sayHello()
方案六: 寄生式组合继承
结合了原型式继承和借用构造函数继承、解决了组合继承父构造函数调用两次的缺点
function Parent(name, hobbies) {
this.name = name,
this.hobbies = hobbies
}
Parent.prototype.sayName = function() {
console.log(this.name);
}
function Child(age, ...args) {
Parent.apply(this, args)
this.age = age
}
// 原型式继承
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child
let son = new Child(8,'zhangsan',['跑步','打球'])
let daughter = new Child(6,'zhangsi', ['跑步', '唱歌'])
son.hobbies.push('打游戏')
console.log('son :>> ', son);
console.log('daughter :>> ', daughter);
方案七: Class es6继承
语法简洁,并且可以在初始化子实例时给父类传参
class Parent {
constructor(name, hobbies) {
this.name = name,
this.hobbies = hobbies
}
sayName() {
console.log(this.name);
}
}
class Child extends Parent {
constructor(age,name, hobbies) {
super(name, hobbies)
this.age = age
}
}
let son = new Child(8, 'zhangsan',['跑步','打球'])
let daughter = new Child(6,'zhangsi', ['跑步', '唱歌'])
son.hobbies.push('打游戏')
console.log('son :>> ', son);
console.log('daughter :>> ', daughter);