js继承

作者: 琴先森的博客 | 来源:发表于2019-02-18 18:00 被阅读0次

前言:构造函数、原型对象、实例

每创建一个构造函数,该函数就会自动带有一个prototype属性,该属性是个指针,指向了一个对象,我们称之为原型对象。原型对象上默认有一个属性constructor,该属性也是一个指针,指向其相关联的构造函数。通过调用构造函数产生的实例,都有一个内部属性,指向了原型对象。

所以三者的关系是:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。通俗点说就是,实例可以通过内部指针访问到原型对象,原型对象通过constructor指针,又可以找到构造函数。

一、js继承之原型继承

前面我们讲到,构造函数产生的实例指向它的原型对象,并且可以访问原型对象上的所有属性和方法。doggie实例指向了Dog的原型对象,可以访问Dog原型对象上的所有属性和方法;如果Dog原型对象变成了某一个类的实例aaa,这个实例又会指向一个新的原型对象AAA,那么doggie此时就能访问aaa的实例属性和AAA原型对象上的所有属性和方法了。同理新的原型对象AAA又碰巧是另外一个对象的实例bbb,这个实例bbb又会指向新的原型对象BBB,那么doggie此时就能访问bbb的实例属性和BBB原型对象上的所有属性和方法了。

这就是JS通过原型链实现继承的方法了。看下面一个例子:

以上代码将Dog的原型对象覆盖成了animal实例。当doggie去访问superSpeak属性时,js会先在doggie的实例属性中查找,发现找不到,然后js就会去doggie的原型对象上查找,原型对象已经被覆盖城了animal实例,那就是去animal实例上去找,先找animal的实例属性,发现还是没有,最后去animal的原型对象上去找,这才找到。这就说明:我们可以通过原型链的方式实现Dog继承Animal的所有属性和方法。总结来说:就是当重写了某一个构造函数的prototype指向的原型对象后,实例的内部指针也发生了改变,指向了新的原型对象,然后就能实现类与类之间的继承了。

缺点:单纯的原型链继承最大的一个缺点,在于对原型中引用类型值的误修改。

我们先看一个例子1:

以上实例实现了Student类对Person类的继承。我们知道所有的Student实例都共享着原型对象上的属性。那么如果我在stu1上改变了head的值,是不是会影响原型对象上的head值呢。看上面的代码就知道,肯定是不会。

原因:当实例中存在和原型对象上同名的属性时,会自动屏蔽原型对象上的同名属性。stu1.head = "聪明的脑袋瓜子" 实际上只是给 stu1 添加了一个本地属性 head 并设置了相关值。所以当我们打印 stu1.head 时,访问的是该实例的本地属性,而不是其原型对象上的 head 属性(它因和本地属性名同名已经被屏蔽了)。

在看例子2:

从上面代码可以看出,如果一个实例不小心修改了原型对象上引用类型的值,会导致其他实例也跟着受影响。

因此,我们得出结论,原型上任何类型的属性值都不会通过实例被重写,但是引用类型的属性值会受到实例的影响而改变。

二、js继承之构造函数继承

在解决原型对象中包含引用类型值所带来问题的过程中,开发人员开始使用一种叫做借用构造函数的技术。实现原理是,在子类的构造函数中,通过apply()、call()和bind()的形式,调用父类构造函数,以实现继承。

在子类函数中,通过call()方法调用父类函数后,子类实例stu1可以访问到Student构造函数和Person构造函数里的所有属性和方法。这样就实现了子类向父类的继承,而且还解决了原型对象上对引用类型值的误修改操作。

缺点:这种形式的继承,每个子类实例都会拷贝一份父类构造函数中的方法,作为实例自己的方法,这样做的缺点:

1.每个实例都拷贝一份,占用内存大。

2.方法都作为了实例自己的方法,当需求改变,要改动其中一个方法时,之前所有的实例他们的该方法都不能及时做出更新。只有后面的实例才能访问到新方法。

call/apply/bind的区别

obj.myFun.call(a, '成都', '上海') //将obj.myFun的this指向了a

obj.myFun.apply(a, ['成都', '上海'])

obj.myFun.bind(a, '成都', '上海')() //bind返回的是一个函数,必须调用才能执行

>> 相同点

* 都代表将obj的this指向a作用域内,a不传或者传null,undefined时this指向window(非严格模式下)

>> 不同点

* call传参方式是逗号隔开

* apply传参是用户数组形式将所有参数一起传

* bind返回的是一个函数,必须调用才能执行,传参方式跟call一样

三、结合使用两种继承模式

综前两点所述,构造函数模式用于定义实例的属性,而原型模式用于定义方法和共享的属性

相关文章

  • Js的继承

    js的继承 @(js)[继承, js, 前端] 组合继承是原性链继承和构造函数继承的合体,它汲取了二者各自的有点,...

  • JS继承

    JS中的继承 许多OO语言都支持两种继承方式:接口继承和实现继承; 因为JS中没有类和接口的概念 , 所以JS不支...

  • #js继承

    js继承的概念 js里常用的如下两种继承方式: 原型链继承(对象间的继承)类式继承(构造函数间的继承) 类式继承是...

  • js继承遇到的小问题

    这两天在看js继承方面,它不像OC那种传统的类继承。js继承方式还是挺多的。比如:原型继承、原型冒充、复制继承 原...

  • JS中继承的实现

    JS中继承的实现 #prototype (js原型(prototype)实现继承) 全局的Function对象没有...

  • js继承

    js继承js 继承-简书 原型链实现集继承 上面的代码实现原型链继承最重要的son.prototype=new f...

  • JavaScript 10

    js继承的概念 1.通过原型链方式实现继承(对象间的继承) 2.类式继承(构造函数间的继承) 由于js不像Java...

  • JS继承的实现的几种方式

    前言 JS作为面向对象的弱类型语言,继承也是非常强大的特性之一,那么如何在JS实现继承呢? JS继承的实现方式 既...

  • 2019-03-25 继承

    js中通过原型来实现继承 组合继承:原型继承+借用构造函数继承

  • 继承方式(6种)1.7

    JS作为面向对象的弱类型语言,继承也是其非常强大的特性之一。那么如何在JS中实现继承呢?让我们拭目以待。 JS继承...

网友评论

      本文标题:js继承

      本文链接:https://www.haomeiwen.com/subject/waxzeqtx.html