segmentfault官方|ES5 继承


北京联盟_本文原题:ES5 继承
作者:assassin cike
来源:SegmentFault 思否社区
首先要明白两点:
一、非方法属性每个子类实例需要独立
二、方法属性每个子类实例需要共享
为什么?
如果非方法属性为引用类型 , 且非方法属性共享 , 在一个实例中改变 , 其他实例中就会做出改变 , 这样每个实例就会相互影响 , 而方法属性一般是不需要进行改变的 , 只是对方法调用 。

  • 方法跟属性分别可以定义在构造函数内部跟prototype上 。
  • 继承的目的是子类继承父类的方法跟属性 。
  • 代码主要来自于红宝书4
基于原型链的继承
每个函数都有个prototype属性,每个对象都有__proto__属性(在chrome中表现如此,prototype也是如此) 如图 , 属性的查找会从当前层级依次向原型链上查找 , 直到查找到原型链的顶端null , 具体可参考:
js proto(https://www.jianshu.com/p/cd26f07df9ba)
segmentfault官方|ES5 继承
本文插图

既然属性的查找是按照原型链向上查找的 , 且继承就是继承父类的属性跟方法 , 那么就可以利用这个特性 , 进行继承 。
functionSuperType{
this.property = true;
}
SuperType.prototype.getSuperValue = http://news.hoteastday.com/a/function{
returnthis.property;
};
functionSubType{
this.subproperty = false;
}
// 继承SuperType
SubType.prototype = new SuperType;
SubType.prototype.getSubValue = http://news.hoteastday.com/a/function{
returnthis.subproperty;
};
letinstance = new SubType;
console.log(instance.getSuperValue); // true可以正确调用父类的方法 , 拿到父类的属性
原型虽然实现了继承 , 但是还是有缺点的
劣势:
1. 子类或者父类的属性为引用类型时 , 改变一个实例的引用类型属性 , 其他实例的该引用类型属性也会发生改变 , 这样其实例就会相互污染了 。
functionSuperType{
this.colors = [ "red", "blue", "green"];
}
functionSubType{} // 继承SuperType
SubType.prototype = new SuperType;
letinstance1 = new SubType;
instance1.colors.push( "black");
console.log(instance1.colors);
// "red,blue,green,black";
letinstance2 = new SubType;
console.log(instance2.colors);
// "red,blue,green,black";
为什么非方法属性不写在prototype上?
因为prototype上的属性的共享的 , 在一个实例上改了该属性 , 其他实例的该属性也会被改掉 。
为什么方法不写在构造函数内部?
  • 方法写在子类内部:每次实例化构造函数 , 方法都是新的;方法只是用来调用 , 不需要修改 , 所以实例共享就行了 。
  • 方法写在父类内部:不同的子类继承父类都需要实例化父类;方法只是用来调用 , 不需要做修改 , 所以实例共享就行了 , 包括子类实例 。 如果子类需要修改父类方法 , 直接在子类中定义相同方法名 , 进行覆盖就行了 。
2. 子类在实例化时不能给父类的构造函数传参 , 因为父类的实例化是在前面 , 而不是构造函数调用的时候 。
盗用构造函数
为了解决父类中属性为引用类型导致子类实例化后 , 引用属性共享的问题 , 跟父类构造函数无法传参的问题 。 引入了“盗用构造函数“方式实现继承 。 思路是在子类构造函数中调用父类构造函数 。