JavaScript继承

2021/9/23 17:13:44

本文主要是介绍JavaScript继承,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

继承

        在ECMAScript中实现继承的方式主要是通过原型链实现的。

1.原型链继承

        通过原型链继承的基本思想是:通过原型,继承引用类型的属性和方法。

注意:所有的引用类型都继承自Object。

        两个函数:Animal、Dog

        一个Dog实例:dog

        通过原型链继承,实现让dog调用sayName()方法

function Animal(name) {
    this.name = name;
}
Animal.prototype.sayName = function () {
    console.log('my name is ', this.name);
}
function Dog(name, color, age) {
    this.name = name;
    this.color = color;
    this.age = age
}
// 原型链继承
Dog.prototype = new Animal();
//修改Dog原型中的constructor指针指向
Dog.prototype.constructor = Dog;
Dog.prototype.sayColor = function () {
    console.log('my color is ', this.color);
}
let dog = new Dog('小白', '白色', 2)
dog.sayColor(); //白色
dog.sayName();   //小白  成功调用该方法
console.log(Dog.prototype.constructor); 
//[Function: Dog]

        当Dog的原型成为Animal的实例时,就实现了原型链的继承。但是Dog里面的constructor指针就会销毁,那么当我们查找dog实例的构造函数时就会向上找到Animal原型的constructor指针,这时,dog的构造函数就为Animal。

        但是,dog的构造函数明明是Dog,通过原型链继承,改变这个指向,所以,我们要手动的修改回来,让他指向回Dog。

        此时,我们就能调用Animal中的sayName()方法。
在这里插入图片描述

1.1 注意
  1. 若我们需要在子类的原型中添加方法,需要在改变子类的constructor指向之后再添加,否则调用不了该方法。

        例如:我们在Dog的原型中添加了一个sayColor()方法,需要在Dog原型的constructor指向改变之后再添加。

  1. 若我们用字面量形式为子类的原型中添加多个方法,那么这就会破坏掉原来的原型链,这样子类的constructor就会指向Object。
Dog.prototype = {
  getDogName() {
    console.log(this.name);
  },
  someOtherMethod() {
    return false;
  }
};
console.log(Dog.prototype.constructor); 
//[Function: Object]
1.2 判断类型

        我们都知道,通过instanceof操作符可以判断一个实例是否属于某个构造函数,即该实例的原型链中是否出现某个构造函数。

isPrototypeOf()

        通过isPrototype()这个方法,我们可以判断某个构造函数的原型链中是否包含某个实例,是则返回true,不是则返回false。

//true
console.log(Object.prototype.isPrototypeOf(dog));
//true
console.log(Animal.prototype.isPrototypeOf(dog));
//true
console.log(Dog.prototype.isPrototypeOf(dog));
1.3 原型链的问题
  1. 当原型中包含引用值时,原型中的引用值会在所有实例中共享,而当引用值被修改时,修改后的值就会被所有实例共享。
  2. 子构造函数在实例化时不能给父构造函数传参。

2.经典继承

        经典继承又称盗用构造函数,用于解决原型包含引用值导致的继承问题

用法:在子构造函数中使用call()或apply()方法,改变this指向,指向当前子构造函数并调用父构造函数。这样之后每个实例都会拥有自己的引用值类型数据,就不会共享而导致出现问题。

// 父'类'
function Animal() {
    this.name = 'aaa'
    this.categorys = ['cat', 'dog']
}
// 子'类'
function Dog() {
    // 改变this指向  继承属性
    Animal.call(this);
}
2.1 经典继承优点
  1. 可在子构造函数中向父构造函数传参
  2. 可给子构造函数的实例添加新的属性
2.2 经典继承的问题
  1. 必须在构造函数中定义方法,导致函数不能重用
  2. 子构造函数不能访问父构造函数原型上定义的方法
  3. 每个子构造函数都拥有父构造函数的副本,浪费内存,影响性能

注意:不能使用instanceof操作符和isPrototypeOf()方法判断继承的父构造函数,因为只继承了父构造函数的实例方法、属性,没有继承父构造函数原型对象中的属性、方法。

3.组合继承

        又称伪经典继承,结合了原型链继承和经典继承的优点,是JS使用最多得继承模式。

用法:通过原型链继承原型上的属性和方法;通过经典继承继承实例属性。

优点:将方法定义在原型上,实现重用;还可以让每个实例都拥有自己的实例

function Animal() {
    this.name = 'aaa'
    this.categorys = ['cat', 'dog']
}
Animal.prototype.sayName = function () {
    console.log(this.name);
}
// 子'类'
function Dog() {
    // 改变this指向 继承属性
    Animal.call(this);
}
// 继承方法
Dog.prototype = new Animal()
var d1 = new Dog();
d1.categorys.push('rabbit')
var d2 = new Dog();
console.log(d1.categorys); //[ 'cat', 'dog', 'rabbit' ]
console.log(d2.categorys); //[ 'cat', 'dog']
d1.sayName()  //aaa


这篇关于JavaScript继承的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程