前言:构造函数、原型对象、实例
每创建一个构造函数,该函数就会自动带有一个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一样
三、结合使用两种继承模式
综前两点所述,构造函数模式用于定义实例的属性,而原型模式用于定义方法和共享的属性

网友评论