JS继承经常会被问到,这两天准备好好整理一下,梳理下各自的优缺点和注意点,以下代码均为手打(因为吃了一次无工具硬编码的亏),在控制台编译通过, 如有不对,敬请指正,谢谢!
一:原型链继承
原型链继承:
一句话描述:将子类的构造函数原型对象指向父类的实例,从而实现原型链继承
function Father(){
this.showArr = [1,2,3];
this.showName = 'Father';
}
function Mother(){
this.showArr = [4,5,6];
this.showName = 'Mother';
}
function Child(){
this.age = 18;
}
var father = new Father();
Child.prototype = father;
Child.prototype.constructor = Child;
var SonA = new Child();
console.log(SonA.showArr); //[1,2,3]
console.log(SonA.showName); //Father
console.log(SonA.age); //18
console.log(Child.showName); //undefined 原型链继承只存在与实例对象和原型对象之间,和构造函数无关
var mother = new Mother();
Child.prototype = mother;
console.log(SonA.showName); //Father SonA._proto_指向并没有改变,还是原来老的,可以参考下面的列子
var SonB = new Child();
console.log(SonB.showArr); //[4,5,6]
console.log(SonB.showName); //Mother
SonB.showArr.push(8); //子类修改了原型中的公用的引用类型值的原型属性
SonB.showName = 'changeName';//子类修改了原型中的公用的非引用类型值的原型属性
var SonC = new Child();
console.log(SonC.showArr); //[4,5,6,8] 成功改变
console.log(SonC.showName); //'Mother' 不改变
重点来分析一下这一句:Child.prototype.constructor = Child;
为什么要重写原型对象的constructor呢,其实如下图所示:
Child.prototype中其实并没有constructor属性,执行这一句是为了为prototype增加constructor属性,并规定其正确的指向。
如下图所示,这样Child.prototype中就有了constructor。但是如果没有写这句,为什么也可以访问到constructor,其实就是根据再原型链上去查找,找到了原型对象上的constructor,也就是Child.prototype.__proto__.constructor(Father)!
那实现继承时为何总是要修正constructor的指向呢?
引用别人的一段话,写的很好:
constructor其实没有什么用处,只是JavaScript语言设计的历史遗留物。由于constructor属性是可以变更的,所以未必真的指向对象的构造函数,只是一个提示。不过,从编程习惯上,我们应该尽量让对象的constructor指向其构造函数,以维持这个惯例。
例子2:
function myObject(){
};
var obj1 = new myObject();
myObject.prototype.type = 'old';
var obj2 = new myObject();
console.log(obj1 instanceof myObject); //true 只是给原型对象myObject.prototype添加了type属性,并没有改变myObject.prototype指向
console.log(obj2