参考地址:阮一峰老师博客
对于JavaScript的继承,看完高级程序设计书本上描述的事例以后没有特别理解;在看完阮一峰老师对于继承这块的描述后,再看回书本里的解释就彻底明白了。
构造一个"人"对象的构造函数。
function Human(){
this.sex = "男";
}
还有一个"男人"对象的构造函数
function Man(name){
this.name = name ;
}
方法一:借用构造函数(又称伪造对象或经典继承)(使用call()或apply()方法,将父对象的构造函数绑定到子对象上)
call()方法接受的是参数列表,而apply()方法接受的是一个参数数组.
function Man(name){
Human.call(this, arguments);
this.name = name;
}
var man1 = new Man("Lux");
console.log(man1.sex); //男
方法二: 原型链
使用prototype对象指向父函数实例,那么子函数的实例就能继承Human
//Man对象指向Huamn实例,实际上是删除了子函数原先的值,
//并赋予一个新值
Man.prototype = new Human();
//每个prototype对象都有constructor属性,指向它的构造函数,
//上面代码实现后,将Man.prototype.constructor指向了Human
//所以需要重新指向回Man,需要以下代码
Man.prototype.constructor = Man;
var man2 = new Man("Lux");
console.log(man2.sex); //男
方法三:直接继承prototype
这种方法是第二种方法的改进
首先改写父函数Human对象
function Human(){ }
Human.prototype.sex = "男";
然后将子函数Man的prototype对象指向Human的prototype对象,完成继承
Man.prototype = Human.prototype;
Man.prototype.constructor = Man;
var man3 = new Man("Lux");
console.log(man3.sex)
这种方法的优点是效率比较高(不再建立和执行Human的实例),比较省内存,缺点是Man.prototype和Human.prototype指向一个对象,改变子函数Man.prototype也会把父函数Human.prototype改变。
第二行代码其实把Human.prototype.constructor也改变了
方法四:原型式继承
var F = function(){ };
F.prototype = Human.prototype;
Man.prototype = new F();
Man.prototype.construction = Man;
F是空对象,所以几乎不占内存。这时,修改Man的prototype对象,就不会影响到Human的prototype对象。
阮老师的封装:
function extend(Child, Parent) {
var F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
Child.uber = Parent.prototype;
}
说明一点,函数体最后一行
Child.uber = Parent.prototype;
意思是为子对象设一个uber属性,这个属性直接指向父对象的prototype属性。(uber是一个德语词,意思是"向上"、“上一层”。)这等于在子对象上打开一条通道,可以直接调用父对象的方法。这一行放在这里,只是为了实现继承的完备性,纯属备用性质。
方法五:拷贝继承
Human不变(方法三一样)
然后写一个函数实现拷贝
function myClone(Child,Parent) {
var p = Parent.prototype;
var c = Child.prototype;
for (var i in p) {
c[i] = p[i];
}
c.uber = p;
}
使用如下:
myClone(Man,Human);
console.log(new Man("Lux").sex); //男