js常见的七种继承及实现_js继承和实现

Animal.call(this, name); // 借用Animal构造函数,并将this指向Dog实例this.age = age;
}

let dog1 = newDog(‘旺财’, 2);
let dog2 = newDog(‘小白’, 1);

console.log(dog1.name); // '旺财’console.log(dog2.age); // 1
dog1.sayName(); // TypeError: dog1.sayName is not a function复制代码


在上面的代码中,Dog类通过调用Animal构造函数来实现继承,从而拥有了Animal类中定义的属性和方法。由于子类实例与父类实例之间不存在原型链的关系,因此修改一个实例的属性不会影响到其他实例。


但是需要注意的是,由于子类实例无法访问父类原型对象上的方法,因此在上面的代码中,dog1实例调用sayName()方法会报错。如果需要在子类中重用父类原型对象上的方法,可以考虑使用组合继承或寄生组合式继承。


优点:


1. 可以向父类构造函数传递参数:借用构造函数继承可以向父类构造函数传递参数,从而可以对父类实例进行初始化。


2. 避免了原型对象共享的问题:由于借用构造函数继承创建了一个新的对象,因此避免了原型对象共享的问题。


3. 可以实现多继承:由于JavaScript中可以在一个构造函数中调用多个构造函数,因此可以通过借用构造函数继承来实现多继承。


缺点:


4. 无法重用父类方法:由于借用构造函数继承创建了一个新的对象,因此无法重用父类的方法。


5. 父类方法更新不会自动同步到子类实例:由于借用构造函数继承创建了一个新的对象,因此父类的方法更新不会自动同步到子类实例中。


6. 无法访问父类原型上的属性和方法:由于借用构造函数继承只继承了父类的实例属性和方法,因此无法访问父类原型上的属性和方法。如果需要访问父类原型上的属性和方法,仍然需要通过将子类的原型指向父类的实例来实现。


#### 3. 组合继承


JavaScript中的组合继承是一种结合借用构造函数和原型链继承的方式,它的核心思想是使用借用构造函数继承实例属性和方法,使用原型链继承共享属性和方法。


以下是一个组合继承的示例代码:



functionAnimal(name) {
this.name = name;
}

Animal.prototype.sayName = function() {
console.log('My name is ’ + this.name);
}

functionDog(name, age) {
Animal.call(this, name); // 借用Animal构造函数,并将this指向Dog实例this.age = age;
}

Dog.prototype = newAnimal(); // 原型链继承Animal类的属性和方法Dog.prototype.constructor = Dog; // 修复构造函数指向let dog1 = newDog(‘旺财’, 2);
let dog2 = newDog(‘小白’, 1);

console.log(dog1.name); // '旺财’console.log(dog2.age); // 1
dog1.sayName(); // 'My name is 旺财’复制代码


在上面的代码中,Dog类通过借用Animal构造函数继承实例属性和方法,通过原型链继承Animal类的属性和方法。由于子类实例与父类实例之间不存在原型链的关系,因此修改一个实例的属性不会影响到其他实例。同时,子类实例可以重用父类原型对象上的方法。


需要注意的是,由于在上面的代码中通过Dog.prototype = new Animal()创建了一个新的Animal实例,因此在创建Dog类时会调用两次Animal构造函数,造成了性能上的浪费。可以使用寄生组合式继承来解决这个问题。


具体来说,组合继承通过将父类的构造函数借用到子类中,从而实现了父类属性的继承,同时通过将子类的原型设置为一个新的父类实例,从而实现了父类方法的继承。这种继承方式具有以下优缺点:


优点:


1. 父类的构造函数可以传递参数,并且不会影响到其他实例。


2. 子类实例可以访问父类原型对象上的方法,可以重用父类的方法。


3. 可以实现多继承。


4. 实现简单、易于理解。


缺点:


5. 子类实例会同时拥有自己的属性和方法,以及父类的属性和方法,可能导致内存浪费和属性名冲突的问题。


6. 在创建子类实例时,父类构造函数会被调用两次,可能会影响性能。


#### 4. 原型式继承


JavaScript中的原型式继承是一种基于已有对象创建新对象的继承方式,它利用了对象的动态特性,通过封装一个函数来实现继承。该函数接收一个用作新对象原型的对象作为参数,并返回一个新对象,从而实现了继承。该方式与借用构造函数继承类似,但它并不涉及到构造函数和实例的概念。原型式继承具有以下特点:


* 基于已有对象创建新对象。


* 可以使用Object.create()方法实现。


* 可以将一个对象作为另一个对象的原型对象。


* 可以使用原型对象的属性和方法,但不会影响到原型对象本身。


下面是一个使用原型式继承的示例代码:



let animal = {
type: ‘animal’,
sayType: function() {
console.log('I am a ’ + this.type);
}
};

let dog = Object.create(animal); // 使用animal对象作为dog对象的原型
dog.type = ‘dog’;

dog.sayType(); // 'I am a dog’复制代码


在上面的代码中,animal对象拥有一个type属性和一个sayType方法,dog对象通过使用animal对象作为原型对象来实现了继承。因此,dog对象可以使用原型对象的属性和方法,但并不会影响到原型对象本身。此外,通过给dog对象添加一个type属性,也可以覆盖原型对象的type属性,实现对父对象属性的重写。原型式继承的优点在于可以方便地实现对象的复用,但也容易导致对象之间的耦合,不易于维护。


具体来说,它通过创建一个空对象,并将其原型设置为一个已有对象,然后向这个空对象中添加属性和方法来实现继承。原型式继承具有以下优缺点:


优点:


1. 简单、易于理解和实现。


2. 可以基于一个对象创建多个对象,实现对象复用。


缺点:


3. 父对象的引用属性会被所有子对象共享,因此子对象的修改会影响到其他子对象。


4. 子对象无法像传统的类继承一样判断自己是否是父对象的实例。


5. 无法实现多继承。


#### 5. 寄生式继承


JavaScript中的寄生式继承是一种基于已有对象创建新对象的继承方式,类似于原型式继承。它的主要区别是,在新创建的对象上增加一个方法,而这个方法的作用是以某种方式增强对象,然后返回这个对象。这种继承方式得名于“寄生”,因为增强对象的方法通常是基于已有的对象进行“寄生”而得名。


寄生式继承的优点是可以封装继承过程,并且可以向对象中添加一些额外的属性和方法。但是和原型式继承一样,也存在父对象的引用属性被所有子对象共享、无法判断实例是否是父对象的实例等问题。


以下是一个使用寄生式继承的示例代码:



functioncreateAnimal(type) {
let animal = {
type: type,
sayType: function() {
console.log('I am a ’ + this.type);
}
};
// 基于animal对象进行寄生增强let dog = Object.create(animal);
dog.bark = function() {
console.log(‘woof woof’);
};
return dog;
}

let myDog = createAnimal(‘canine’);
myDog.sayType(); // ‘I am a canine’
myDog.bark(); // 'woof woof’复制代码


在上面的代码中,我们定义了一个名为createAnimal的函数,用于创建一个继承自animal对象的新对象。我们在这个新对象上增加了一个bark方法,用于让对象发出叫声。最后,我们返回这个新对象,并将它赋值给myDog变量。通过这样的方式,我们成功地实现了寄生式继承。


具体来说,它在原型式继承的基础上增加了一个包装函数,该函数用于封装继承过程中的一些增强行为。寄生式继承具有以下优缺点:


优点:


1. 简单、易于理解和实现。


2. 可以基于一个对象创建多个对象,实现对象复用。


3. 可以在不修改原对象的情况下,对继承过程进行一些增强,例如添加新的属性和方法。


缺点:


4. 父对象的引用属性会被所有子对象共享,因此子对象的修改会影响到其他子对象。


5. 子对象无法像传统的类继承一样判断自己是否是父对象的实例。


6. 增强行为可能会带来一定的性能开销。


7. 可能会导致代码的可读性降低。


#### 6. 寄生式组合继承


JavaScript中的寄生式组合继承是一种结合了组合继承和寄生式继承的继承方式。具体来说,它在组合继承的基础上,通过寄生式继承来解决组合继承中重复调用父构造函数的问题。


下面是一个使用寄生式组合继承的示例代码:



functionAnimal(name) {
this.name = name;
this.type = ‘mammal’;
}

Animal.prototype.sayName = function() {
console.log('My name is ’ + this.name);
};

functionDog(name, breed) {
Animal.call(this, name);
this.breed = breed;
}

// 使用寄生式继承继承Animal.prototypeDog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.sayBreed = function() {
console.log('I am a ’ + this.breed);
};

let myDog = newDog(‘Max’, ‘Golden Retriever’);
myDog.sayName(); // ‘My name is Max’
myDog.sayBreed(); // 'I am a Golden Retriever’复制代码


在上面的代码中,我们定义了Animal和Dog两个构造函数,其中Animal构造函数定义了一个name属性和一个sayName()方法,Dog构造函数在Animal的基础上添加了一个breed属性和一个sayBreed()方法。为了实现寄生式组合继承,我们使用Object.create()方法基于Animal.prototype创建了一个新的对象,并将其赋值给Dog.prototype,从而使得Dog.prototype的原型链指向了Animal.prototype。同时,我们还将Dog.prototype的constructor属性设置为Dog,以保证继承链的完整性。最后,我们通过调用Animal构造函数并将this指向Dog对象,实现了对Animal属性的继承。通过这种方式,我们既避免了组合继承中重复调用父构造函数的问题,又保留了寄生式继承的灵活性,实现了一个高效而且灵活的继承方式。


优点:


1. 实现了属性和方法的完整继承。


2. 避免了组合继承中重复调用父类构造函数的问题,提高了性能。


3. 可以在不修改原对象的情况下,对继承过程进行一些增强,例如添加新的属性和方法。


缺点:


4. 增加了一层包装函数,可能会带来一定的性能开销。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值