关于继承
看各种资料,介绍继承,从这么几方面来说:
1. 原型继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function Father(){ this.property = true; } Father.prototype.getFatherValue = function(){ return this.property; } function Son(){ this.sonProperty = false; }
Son.prototype = new Father();
Son.prototype.getSonVaule = function(){ return this.sonProperty; } var instance = new Son(); alert(instance.getFatherValue());
|
问题:当原型链中包含引用类型值的原型时,该引用类型值会被所有实例共享;并且这种继承硬编码的方式导致父类不能接收参数。
2. 借用构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13
| function Father(){ this.colors = ["red","blue","green"]; } function Son(name){ Father.call(this); this.name = name; } var instance1 = new Son(); instance1.colors.push("black"); console.log(instance1.colors);
var instance2 = new Son(); console.log(instance2.colors);
|
解决了父类引用类型数据被共享的问题,但是没有继承父类的原型方法。
3. 组合继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| function Father(name){ this.name = name; this.colors = ["red","blue","green"]; } Father.prototype.sayName = function(){ alert(this.name); }; function Son(name, age){ Father.call(this, name); this.age = age; } Son.prototype = new Father(); Son.prototype.sayAge = function(){ alert(this.age); } var instance1 = new Son("louis",5); instance1.colors.push("black"); console.log(instance1.colors); instance1.sayName(); instance1.sayAge();
var instance1 = new Son("zhai",10); console.log(instance1.colors); instance1.sayName(); instance1.sayAge();
|
解决了父类引用类型变量被共享和不能继承原型方法的问题。但是继承父类方法的时候,调用 new Father () 时,将 Father 的实例属性添加到 Son 的原型中,而这些属性在构造借用时已经添加到 Son 实例上了(相当于 Son.prototype 上这些 Father 的属性重复且无用)
4. 寄生组合式继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| function extend(subClass, superClass){ var prototype = Object.create(superClass.prototype); prototype.constructor = subClass; subClass.prototype = prototype; }
function Father(name){ this.name = name; this.colors = ["red","blue","green"]; }
Father.prototype.sayName = function(){ alert(this.name); }; function Son(name, age){ Father.call(this, name); this.age = age; } extend(Son,Father); Son.prototype.sayAge = function(){ alert(this.age); } var instance1 = new Son("louis",5); instance1.colors.push("black"); console.log(instance1.colors); instance1.sayName(); instance1.sayAge();
var instance1 = new Son("zhai", 10); console.log(instance1.colors); instance1.sayName(); instance1.sayAge();
|
这样是最优解。
疑问
- 为什么原型继承那里不用 subClass.prototype = superClass.prototype?
其实因为如果这样做的话,对对象进行 instanceOf 的时候就会出问题。比如我 new 了一个 superClass 对象 super1,但中间执行过 extend (subClass, superClass) 这个方法,那么子类的 proto 就指向了 super 的 proto。造成的结果是 super1 instanceOf superClass === true(没毛病),super1 instanceOf subClass === true (瓦特?)。所以中间用一个过渡的对象,防止这种情况的发生。