今天课下玩的时候遇到一个问题(其实我只是一个做设计的小美工)
代码如下:
function Aa() { this.num = [1, 2, 3]; } function Bb() {}; Bb.prototype = new Aa(); var ins1 = new Bb(); ins1.num.push(4); console.log(ins1.num); // 1, 2, 3, 4 var ins2 = new Bb(); console.log(ins2.num); // 1, 2, 3, 4
天真的我以为 ins2.num 打印出来还是原数组,
然后再次翻了下红宝书的原型部分大致意思如下:
原型链实现继承后,如果超类构造函数定义了一个属性而它的值是引用类型,
那么子类构造函数即将new出来的每一个实例都会共享这个属性。
注:子类继承超类
为什么呢? 因为子类构造函数的原型指向的是超类的实例啊 Bb.prototype = new Aa();
那么就理所当然超类的构造函数属性和原型属性都被添加到了子类的原型上,
所以子类即将new出来的每一个实例共享那一个属性。
借用构造函数
为了解决上述的问题,一种叫“借用构造函数”的技术诞生了。
方法很简单 只需你理解了apply()和call()方法。不懂的话可以看我的这篇《apply/call/bind的区别与用法》。
代码如下:
function Aa() { this.num = [1, 2, 3]; } function Bb() { // 继承了Aa Aa.call(this); }; Bb.prototype = new Aa(); var ins1 = new Bb(); ins1.num.push(4); console.log(ins1.num); // 1, 2, 3, 4 var ins2 = new Bb(); console.log(ins2.num); // 1, 2, 3
那么现在又有一个问题出现了
我们用这种方法继承后 如果在超类的原型上定义方法Aa.prototype.get1 = function () {console.log(‘get1‘)};
子类是找不到超类原型上的get1方法的。
组合继承
这时js大佬们搞出了 “组合继承” 也是最常用的一种继承模式。
function Aa() { this.num = [1, 2, 3]; } Aa.prototype.get1 = function () {console.log(‘get1‘)}; function Bb() { // 继承属性 Aa.call(this); }; // 继承方法 Bb.prototype = new Aa(); Bb.prototype.constructor = Bb; Bb.prototype.get2 = function () {console.log(‘get2‘)}; var ins1 = new Bb(); ins1.num.push(4); console.log(ins1.num); // 1, 2, 3, 4 ins1.get1(); // get1 ins1.get2(); // get2 var ins2 = new Bb(); console.log(ins2.num); // 1, 2, 3 ins2.get1(); // get1 ins2.get2(); // get2