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
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值