JavaScript中实现继承的6种方法

JavaScript中实现继承的6种方法

在JavaScript中,继承是一项非常重要的概念。它允许开发人员创建一个对象,该对象具有与另一个对象共享的属性和方法。通过继承,可以轻松地扩展现有代码并减少代码的重复。本篇文章将介绍JavaScript中实现继承的6种方法。

1.原型链继承

原型链继承是JavaScript中最基本的继承方式。它的工作原理是创建一个新对象,该对象的原型为要继承的对象。通过将函数添加到原型中,可以将其继承到该新对象中。以下是一个使用原型链实现继承的例子:

function Animal(){

this.name = 'Animal';

this.sleep = function(){

console.log(this.name + ' is sleeping');

}

}

Animal.prototype.eat = function(food){

console.log(this.name + ' is eating ' + food);

};

function Cat(){

this.name = 'Cat';

}

Cat.prototype = new Animal();

var cat = new Cat();

console.log(cat.name);

console.log(cat.sleep());

console.log(cat.eat('fish'));

以上代码中,我们定义了一个Animal函数,它有一个name属性和一个原型方法eat。然后我们定义了一个Cat函数,这个函数并没有定义任何属性和方法。接着我们通过将Cat的原型设置为一个Animal的实例,来实现继承。最后,我们创建了一个Cat实例并测试了它的属性和方法。cat实例继承了Animal的属性和方法,打印出了'Cat'和'Animal is sleeping',并成功调用了eat方法。

但是原型链继承也有它的问题。由于对象共享同一个原型,所以对于原型上的引用类型的属性的修改会影响到所有继承的对象。改写上面的例子:

function Animal(){

this.name = 'Animal';

this.sleep = function(){

console.log(this.name + ' is sleeping');

}

this.features = {

hair: true

}

}

Animal.prototype.eat = function(food){

console.log(this.name + ' is eating ' + food);

};

function Cat(){

this.name = 'Cat';

}

Cat.prototype = new Animal();

var cat1 = new Cat();

var cat2 = new Cat();

console.log(cat1.features.hair);

cat2.features.hair = false;

console.log(cat1.features.hair);

在以上代码中,Animal原型上的特征是一个对象,cat1和cat2都继承了这个对象。修改cat2的属性,也会影响cat1的属性。因为cat1和cat2都是通过一个原型创建出来的。这个问题可以通过利用构造函数继承来解决。

2.构造函数继承

在JavaScript中,每个函数都有一个prototype属性,该属性指向一个对象。当使用new操作符创建一个新对象时,将返回一个新对象,该对象的原型为构造函数的原型。因此,可以在构造函数中定义一个对象,然后通过调用该对象上的方法来实现继承。以下是一个使用构造函数实现继承的例子:

function Animal(){

this.name = 'Animal';

this.sleep = function(){

console.log(this.name + ' is sleeping');

}

}

Animal.prototype.eat = function(food){

console.log(this.name + ' is eating ' + food);

};

function Cat(){

Animal.call(this);

this.name = 'Cat';

}

var cat = new Cat();

console.log(cat.name);

console.log(cat.eat('fish'));

console.log(cat.sleep());

在以上代码中,我们定义了一个Animal构造函数和一个Cat构造函数。当我们在Cat构造函数中调用Animal.call(this)时,Animal的属性和方法就会继承到Cat中。这就是构造函数继承的本质。此时,cat实例可以访问Animal的方法和属性,但是它并没有继承Animal原型上的方法。同时,由于并未使用原型链,所以没有访问Animal其他实例的属性和方法的能力。构造函数继承的缺点是,每个新实例都需要独立创建一遍方法。这会使内存占用率增加。

3.组合继承

组合继承是最常用的继承方式。它结合了原型链继承和构造函数继承的优点。组合继承的本质是通过原型链实现对原型属性和方法的继承,通过借用构造函数实现对实例属性的继承。这使得每个新实例既具有了其父类的属性和方法,又具有了其自己的属性和方法。以下是一个组合继承的例子:

function Animal(){

this.name = 'Animal';

this.features = {

hair: true

}

}

Animal.prototype.sleep = function(){

console.log(this.name + ' is sleeping');

}

Animal.prototype.eat = function(food){

console.log(this.name + ' is eating ' + food);

};

function Cat(){

Animal.call(this);

this.name = 'Cat';

}

Cat.prototype = new Animal();

Cat.prototype.constructor = Cat;

var cat = new Cat();

console.log(cat.name);

console.log(cat.features.hair);

console.log(cat.eat('fish'));

console.log(cat.sleep());

在以上代码中,我们首先通过constructor属性指定原型链上Cat函数的构造函数。然后,我们创建Cat构造函数的实例,并将其原型指向Animal实例。通过该方式,Cat实例既可以继承Animal的属性和方法,也可以在构造函数中定义自己的属性。同时,这种方式克服了原型链继承的缺点,因为每个实例都是独立创建方法的。

4.原型式继承

原型式继承是一种简单的继承方式。它通过创建一个空对象作为新对象,并将该对象的原型设置为要继承的对象,从而将要继承对象的属性和方法继承到新对象中。以下是一个使用原型式继承实现继承的例子:

var animal = {

name: 'Animal',

features: {

hair: true

}

};

var cat = Object.create(animal);

console.log(cat.name);

console.log(cat.features.hair);

在以上代码中,我们首先定义了一个animal对象,它有一个name属性和一个特性features。然后我们创建了一个cat对象,并将其原型设置为animal对象。cat继承了animal对象的属性和方法。

我们还可以使用Object.create()方法的第二个参数来定义新对象的属性,这些属性将覆盖继承的属性。以下是一个使用原型式继承实现属性覆盖的例子:

var animal = {

name: 'Animal',

features: {

hair: true

}

};

var cat = Object.create(animal,{

name: {

value: 'Cat'

}

});

console.log(cat.name);

console.log(cat.features.hair);

在以上代码中,我们使用Object.create()方法的第二个参数,来为新对象设置属性。由于该属性与父对象的属性重名,就会覆盖父对象的属性。这样,cat会继承animal的特性,但是它的name属性被设置为'Cat'。

5.寄生式继承

寄生式继承是另一种简单的继承方式。它本质上是在使用原型式继承创建新对象的基础上,增强了该对象,然后返回它。以下是一个使用寄生式继承实现继承的例子:

function createCat(obj){

var cat = Object.create(obj);

cat.name = 'Cat';

cat.sleep = function(){

console.log(this.name + ' is sleeping');

};

return cat;

}

var animal = {

name: 'Animal'

};

var cat = createCat(animal);

console.log(cat.name);

console.log(cat.sleep());

在以上代码中,我们定义了一个createCat函数,它首先使用Object.create()方法创建一个新对象cat,并将其原型设置为要继承的对象。然后我们增强了cat对象,并返回它。cat对象继承了animal对象的属性和方法,同时也具有它自己的方法。

6.寄生组合式继承

寄生组合式继承是对组合继承的一种优化。它通过使用Object.create()方法来实现对父对象的一次浅拷贝,从而避免了调用父构造函数的问题。以下是一个使用寄生组合式继承实现继承的例子:

function Animal(){

this.name = 'Animal';

this.features = {

hair: true

}

}

Animal.prototype.sleep = function(){

console.log(this.name + ' is sleeping');

};

Animal.prototype.eat = function(food){

console.log(this.name + ' is eating ' + food);

};

function Cat(){

Animal.call(this);

this.name = 'Cat';

}

Cat.prototype = Object.create(Animal.prototype);

Cat.prototype.constructor = Cat;

var cat = new Cat();

console.log(cat.name);

console.log(cat.features.hair);

console.log(cat.eat('fish'));

console.log(cat.sleep());

在以上代码中,我们首先创建Animal和Cat函数,并使用Animal.call(this)方法在Cat构造函数中调用Animal函数。然后,我们通过Object.create()方法创建一个新对象,并将其原型设置为Animal原型,以实现对Animal属性和方法的继承。通过这种方式,Cat对象继承了Animal对象的属性和方法,同时又避免了调用父构造函数的问题。

总结

本篇文章介绍了JavaScript中实现继承的6种方法。每种继承方式都有其优点和缺点。在实际情况下,根据不同的需求和应用场景,选择不同的继承方式。继承是JavaScript中一个非常重要的概念,熟练掌握各种继承方式对于编写高质量、易于维护的代码是至关重要的。