javascript基于原型链的继承及call和apply函数用法分析

在面向对象编程中,继承是一种允许新对象获取现有对象的属性和方法的机制。它允许我们创建继承现有对象的新对象,从而减少代码重复,增加代码可重用性。

JavaScript基于原型链的继承

什么是继承

在面向对象编程中,继承是一种允许新对象获取现有对象的属性和方法的机制。它允许我们创建继承现有对象的新对象,从而减少代码重复,增加代码可重用性。

JavaScript中基于原型链的继承

在JavaScript中,没有像其他语言一样的类和接口的概念,继承通过原型链来实现。每个对象都有一个原型对象,原型对象又有自己的原型对象,形成一个链式结构,最后的节点是null。

当访问一个对象的属性或方法时,如果该对象本身没有,它会沿着原型链向上查找,直到找到该属性或方法或者查找到null为止。

实现方式

JavaScript中实现继承可以通过以下几个方式:

1.原型链继承

原型链继承是将子类的原型指向父类的实例来实现继承,子类的实例就可以使用父类的属性和方法。原型链继承的一个缺点是由于所有子类的实例共享同一个父类实例,因此一个子类实例中的数据改变了,其他子类实例的数据也会被改变。

function Parent(name) {
    this.name = name;
}
Parent.prototype.getName = function() {
    console.log(this.name);
}

function Child(name) {
    this.name = name;
}
Child.prototype = new Parent();

var child1 = new Child('child1');
var child2 = new Child('child2');
child1.getName(); // 输出:child1
child2.getName(); // 输出:child2

console.log(child1 instanceof Child); // 输出:true
console.log(child1 instanceof Parent); // 输出:true

2.借用构造函数继承

借用构造函数继承是通过在子类构造函数中调用父类的构造函数来实现继承。利用call或apply方法可以实现借用构造函数继承。借用构造函数继承的一个缺点是父类的原型对象中定义的方法无法被子类继承。

function Parent(name) {
    this.name = name;
    this.getName = function() {
        console.log(this.name);
    }
}

function Child(name) {
    Parent.call(this, name);
}

var child = new Child('child');
child.getName(); // 输出:child

console.log(child instanceof Child); // 输出:true
console.log(child instanceof Parent); // 输出:false

3.组合继承

组合继承是同时使用上面两种方式实现继承。通过原型链继承父类原型对象中的属性和方法,再通过借用构造函数继承父类中的属性和方法。组合继承既可以继承原型对象中的方法,又可以继承构造函数中的属性,但它也有一个缺点是调用了两次父类的构造函数。

function Parent(name) {
    this.name = name;
}
Parent.prototype.getName = function() {
    console.log(this.name);
}

function Child(name) {
    Parent.call(this, name);
}
Child.prototype = new Parent();

var child = new Child('child');
child.getName(); // 输出:child

console.log(child instanceof Child); // 输出:true
console.log(child instanceof Parent); // 输出:true

call和apply函数用法分析

callapply都是用来动态改变函数运行时的this绑定的。

call函数

call函数的语法格式:function.call(thisArg, arg1, arg2, ...)

其中:

  • thisArg表示当前函数运行时的this绑定对象
  • arg1, arg2, ...表示传递给当前函数的参数列表,多个参数之间用逗号分隔

通过call函数,我们可以改变函数运行时的this绑定对象。

function greet(word) {
    console.log(word + ',' + this.name);
}

var person = { name: 'Jack' };
greet.call(person, 'Hello'); // 输出:Hello,Jack

apply函数

apply函数的语法格式:function.apply(thisArg, args)

其中:

  • thisArg表示当前函数运行时的this绑定对象
  • args表示传递给当前函数的参数列表,以数组的形式传递

通过apply函数,我们可以将数组作为参数传递给函数。

function greet(word1, word2) {
    console.log(word1 + ',' + word2 + ',' + this.name);
}

var person = { name: 'Jack' };
greet.apply(person, ['Hello', 'Hi']); // 输出:Hello,Hi,Jack

示例说明

示例1

下面是一个继承的例子,利用函数的继承可以减少代码重复。

function Animal(name) {
    this.name = name;
}
Animal.prototype.getSound = function() {
    console.log('Animal sound');
}

function Dog(name) {
    Animal.call(this, name);
}
Dog.prototype = new Animal();
Dog.prototype.getSound = function() {
    console.log('Wang Wang');
}

var dog = new Dog('Tom');
dog.getSound(); // 输出:Wang Wang
console.log(dog.name); // 输出:Tom

示例2

下面是一个使用call函数的例子,将一个对象的方法应用到另一个对象上。

function greet(word) {
    console.log(word + ',' + this.name);
}

var obj1 = { name: 'Jack' };
var obj2 = { name: 'Tom' };

greet.call(obj1, 'Hello'); // 输出:Hello,Jack
greet.call(obj2, 'Hi'); // 输出:Hi,Tom

通过上面的例子,我们可以看到call函数的灵活性,它可以将对象的方法应用到另一个对象上。

本文标题为:javascript基于原型链的继承及call和apply函数用法分析

基础教程推荐