(文章纯粹自己的理解,如果有问题请留言或私信)
继承的目的:
1) 复用方法(父的方法)
2) 有权添加/重写父的方法
3)不允许添加/重写父方法/属性的时候污染到父类
通常被认为是完美继承的就是:寄生组合继承
1.为什么我认为他们不够完美呢?
这里解释一下,不是觉得寄生组合继承不够完美,而是大多数都没搞懂什么是寄生组合继承。
虽然他们的结果没什么问题,达到的效果很不错。但是,作为处女座的我,依旧对他们的代码感到一股强烈的违和感。要么污染了父类,要么结构混乱,要么程序复杂,要么多次继承的时候麻烦。
2.接下来我会讲解一下我认为完美的继承:
其实这个继承的方法不用我们自己去想,JS已经提供了。
废话不多说直接上图:
图中有一点不好表达,我说明一下:
图中Woman构造器的prototype对象包含了一个person实例对象,但是我要表达的是Woman构造器的prototype对象包含了person实例对象的所有内容。
还有就是“指向”的线条类似指针的效果,通过constructor能够访问到对于的构造器。
其中:
Person、Woman、YellowMan都是function出来的构造器对象(也是函数)
而YellowMan继承了Woman,Woman继承了Person,而Person是初代。
这里说明一下,prototype属性和__proto__属性都是对象,而且他们的所有者都能够直接访问其内部的属性,而且能够像套娃一样访问,这也是我们继承的理论基础,只不过优先级并不一样,所有者自己直属属性>__proto__内部>prototype内部。
还有一点就是构造器实例化的时候,实例的__proto__属性是和构造器的prototype属性相同的,都指向相同的对象数据类型的一块内存。同时,实例的过程实际上还通过构造器的name属性找到了构造器函数,进行了一次call函数,就完成了属性的实例化。
图2解释了部分Object构造器对象和Function构造器对象的关系,对象o和对象f是没有名字的两个对象,但是在整个结构里很重要所以一起列出来。
从图1里我们应该能看到这种继承看起来就很舒服,至于“指向”的那条线只是为了跟随初代的脚步,作用大概就是在整个链路里保存构造器。
最后,按照图示逻辑写代码如下(输出结果可以自行实验,我得到的结果很完美):
(补充一句:call函数用不用都行。我更倾向于不使用call,因为每次继承都要call一下实在不爽,而且数据就结构和初代继承会不一样,再有一点就是变量的优先级容易发生混淆。call函数如果在自定义属性的后面,那么你自定义的属性将没法覆盖继承来的值,渣渣)
//========公共继承用函数========
//继承父类
function myInherit(son,father){
//父类的实例作为子类的原型
son.prototype = new father();
//修复构造函数指向问题
son.prototype.constructor = son;
}
//========公共继承用函数========
//========父类========
function Person(name,age){
this.name = name || 'wangxiao';
this.age = age || 27;
}
//父类方法
Person.prototype.eat = function(){
return this.name + this.age + 'eat sleep';
}
//========父类========
//========第一级继承========
function Woman(){
this.gender="female";
this.age=38;//覆盖
}
//使用公共的继承函数
myInherit(Woman,Person);
//添加方法,如果要在构造器外添加,一定要放在继承函数后面,防止覆盖
Woman.prototype.birth=function(){
return this.name + this.age + this.gender + 'eat sleep pregnant';
}
//实例化
let womanObj = new Woman();
//输出结果
console.dir(womanObj.name);
console.dir(womanObj.age);
console.dir(womanObj.gender);
console.dir(womanObj.birth());
//========第一级继承========
//========第二级继承========
function YellowWoman(){
this.color="yellow";
this.age=40;//覆盖
}
//使用公共的继承函数
myInherit(YellowWoman,Woman);
//添加方法,如果要在构造器外添加,一定要放在继承函数后面,防止覆盖
YellowWoman.prototype.sleep=function(){
return this.name + this.age + this.gender + this.color + 'eat sleep pregnant yellow';
}
//实例化
let yellowWomanObj = new YellowWoman();
//输出结果
console.dir(yellowWomanObj.name);
console.dir(yellowWomanObj.age);
console.dir(yellowWomanObj.gender);
console.dir(yellowWomanObj.color);
console.dir(yellowWomanObj.sleep());
//========第二级继承========