继承:就是让子对象获得父对象的属性和方法的一种方式。它的内容还是蛮复杂的,方式多样!
1、对象冒充实现的继承
理解:函数,既是方法,也是对象。一个函数(以方法身份)就可以作为另一个函数(以对象身份)的方法
function ClassA(sColor) {
this.color = sColor;
this.sayColor = function(){
alert(this.color);
}
}
// 构造函数中的 this 指向的是新创建的对象
function ClassB(sColor, sName) {
this.newMethod = ClassA; //ClassA中的this指向所属的对象
this.newMethod(sColor); //传入参数调用了
delete this.newMethod; //这个地方其实不太理解,既然delete,为啥还可以调用
this.name = sName;
this.sayName = function(){
alert(this.name);
}
}
var objA = new ClassA("red");
var objB = new ClassB("green", "luo");
objA.sayColor(); //"red"
objB.sayName(); //"green"
2、函数方法 call()和 apply() 实现的继承
理解:call()
和 apply()
可以改变函数的作用对象,不同的对象可以调用同一函数
function ClassA(sColor) {
this.color = sColor;
this.sayColor = function(){
alert(this.color);
}
}
// 构造函数中的 this 指向的是新创建的对象
function ClassB(sColor, sName) {
ClassA(this, sColor); //this当前调用函数的对象,后面是参数
this.name = sName;
this.sayName = function(){
alert(this.name);
}
}
var objA = new ClassA("red");
var objB = new ClassB("green", "luo");
objA.sayColor(); //"red"
objB.sayName(); //"green"
3、原型链实现的继承
理解:原型链继承的本质就是,每个构造函数以及该构造函数生成的对象都有个prototype
属性,都指向同一个原型对象。因此第二个函数的原型属性就可以用第一个函数的实例对象来充当,这样就构成了一层一层的继承关系。Class2.prototype = new Class1()
原型属性等于不带参数的构造函数实例
function SuperType(){ this.superProperty = true; } SuperType.prototype.getSupProperty = function(){ alert(this.superProperty); } function SubType(){ this.subProperty = false; } SubType.prototype = new SuperType(); //子类原型等于父类实例 SubType.prototyep.getSubProperty = function(){ alert(this.subProperty); }
理解:子类原型对象等于构造函数的实例,这时候的构造函数没有传参数。如果要传参数,就会用到 curry
化,但是就得将原型对象放在构造函数内部,这个是不允许的。
对象冒充继承属性,原型继承方法
function ClassA(sColor) { this.color = sColor; } ClassA.prototype.sayColor = function() { alert(this.color); } function ClassB(sColor, sName) { ClassA.call(this, sColor); this.name = sName; } ClassB.prototype = new ClassA(); ClassB.prototype.sayName = function() { alert(this.name); } var objA = new ClassA("red"); var objB = new ClassB("green", "luo"); objA.sayColor(); //"red" objB.sayColor(); //"green"
4、原型链继承中构造函数带参数
在用原型链继承时,
ClassB.prototype = new ClassA()
,子类的原型对象上已经包含了父类构造函数里的自定义属性,因为没有传参数,所以这个值为空。但本质上,这个父类元素实例化赋给子类原型时,是可以带参数的,因此子类也就可以访问父类的这个属性,也可以理解为继承了这个属性(这是原型链的继承过程)。
function ClassA(sColor) {
this.color = sColor;
}
ClassA.prototype.sayColor = function() {
alert(this.color);
};
function ClassB(sName) {
this.name = sName;
}
// 将传入了参数的实例化对象赋给原型对象
ClassB.prototype = new ClassA("green");
var objA = new ClassA("red");
var objB = new ClassB("luo");
objA.sayColor(); //"red"
alert(objB.name); //"luo" 这个是本对象的,构造函数实例化时有的
alert(objB.color); //"green 这个是原型对象上有的,即带参数的实例化对象里的
这里面其实已经实现了“传参数的实例化对象赋给原型对象”,并且也继承了,到从代码的直观上来说,好像ClasB(sName)
就一个name属性,其实它还有个color属性,只是放在了原型对象上,不够直观,容易误解。
==5、Obejct.setPrototypeOf(obj, newPrototype)
实现的属性继承==
在第三中方案里,我们是通过“对象冒充”继承属性,“原型对象”继承方法。但终究感觉不太好,因为当
ClassB.prototype = new ClassA()
时,已经继承了属性,只是这个属性为空,并且还被“对象冒充”继承的属性给提前拦截了,覆盖了,访问不到这一层。
function ClassB(sColor, sName) {
this.name = sName;
return (function(sColor) {
ClassB.prototype = new ClassA(sColor);
})();
//按道理,这样应该也可行的
Object.getPrototypeOf(this) = new ClassA(sColor);
}
var objB = new ClassB("green", "luo");
alert(objB.color); //undefined
我想实现的就是类似这种效果,但是都娶不到。
终于找到最优的解法了:
ClassA.prototype.sayColor = function() {
alert(this.color);
};
function ClassB(sColor, sName) {
this.name = sName;
Object.setPrototypeOf(this, new ClassA(sColor));
}
ClassB.prototype.sayName = function() {
alert(this.name);
};
var objA = new ClassA("red");
var objB = new ClassB("green", "luo");
objA.sayColor(); //"red"
alert(objB.color); //"green
Object.setPrototypeOf(this, new ClassA(sColor));
完美的解决了原型链继承中,属性继承的方法,而不是“对象冒充”。只是这个方法的性能好像有点影响。
提个小问题:怎么感觉原型链上的这个
this
好像传的比较远???现在才懂,但这毕竟是自己理解下亲自解决的方法。虽然说,这个方法肯定早已存在,它就在那个地方等着,只是你现在才发现而已。但是,一开始的全盘告诉你,你能接受得了吗?所以,一切都只能自己去发掘,既然它早已存在,对于你而言肯定是越早发现越好。
有一点,无论你发掘了什么东西,解决了什么问题,永远不要得意忘形,因为永远还有很多东西是你不知道的,你对于大千世界而言,永远都是渺小的。
吾生也有涯,而知也无涯,以有涯随无涯,殆矣。
而人生,就是这种学习探索的过程。
我才知道了,当你学习一样东西,如果你学到的真的就只是那一样东西,那最终你什么也没学到。你学到的是一些死货,没了多少的意义。你真正需要学习的是里面的设计思想,何为设计思想?就是里面设计的主线,也即机制,比如说:面向对象,你真的懂什么是面向对象么?所谓的面向对象就是一切皆对象,对象的身上附带着方法与属性,所有的使用也是基如此。为什么这样说呢?因为我花了很长时间都没有学懂的
indexedDB
原来也是奉行这一套,在此基础上执行原型链的那一套继承方式。