在面向对象编程中,继承是一种允许新对象获取现有对象的属性和方法的机制。它允许我们创建继承现有对象的新对象,从而减少代码重复,增加代码可重用性。
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函数用法分析
call
和apply
都是用来动态改变函数运行时的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函数用法分析
基础教程推荐
- Java中OAuth2.0第三方授权原理与实战 2022-11-25
- SpringBoot使用AOP记录接口操作日志的方法 2023-03-22
- jpa使用注解生成表时无外键问题及解决 2023-01-24
- JAVA中的SQL Server查询通知 2023-11-06
- Mybatis源码解析之事务管理 2023-08-08
- 浅谈servlet与jsp的关系 2024-03-01
- Spring @Cacheable指定失效时间实例 2023-08-10
- Spring Bean的线程安全问题 2022-11-29
- SpringBoot测试配置属性与web启动环境超详细图解 2023-06-17
- 关于RedisTemplate之opsForValue的使用说明 2022-12-03