JavaScript中的继承
JavaScript中的继承有多种实现,我们一步步来,层层深入下。
一、 原型继承,又称类式继承。
实现:将父类的示例赋值给子类的原型对象prototype。
代码示例:
function SuperType() { this.prop = 'super'; }; SuperType.prototype.getName = function () { console.log(this.prop); }; function SubType() { this.subProp = 'sub'; }; SubType.prototype = new SuperType(); // 原型继承的精华 var sub = new SubType(); sub.getName(); // super console.log(sub.subProp) // sub
解释:将父类的示例赋值给子类的原型对象prototype,则子类的原型对象不仅会拥有父类构造函数中的所有属性和方法,还会拥有父类原型对象中的属性和方法。
因此在实例化子类对象时,子类不仅会执行子类的构造函数,拥有子类构造函数中的属性和方法,还会继承来自子类原型上的属性和方法,
而子类原型上的属性和方法已通过 SubType.prototype = new SuperType() 拥有了父类构造函数和父类原型上的属性和方法,
从而子类也拥有了父类构造函数和父类原型上的属性和方法。。。
缺点:
1. 如果父类中的共有属性是引用类型,就会在子类实例中被所有实例公用。
2. 由于子类实现的继承是靠其原型对父类实例化实现的,因此在创建父类的时候是无法像父类传参的。
function SuperType() { this.arr = ['aa', 'bb']; }; function SubType() {}; SubType.prototype = new SuperType(); var sub1 = new SubType(); var sub2 = new SubType(); sub1.arr.push('cc'); console.log(sub1.arr); // ["aa", "bb", "cc"] console.log(sub2.arr); // ["aa", "bb", "cc"]
二、构造函数继承
实现:在子类构造函数中执行一遍父类的构造函数。
代码实例:
function SuperType(prop) { this.superProp = prop; this.arr = ['aa', 'bb']; }; SuperType.prototype.getArr = function () { console.log(this.arr); }; function SubType(prop) { SuperType.call(this, prop); // 可以传参 }; var sub1 = new SubType('super1'); var sub2 = new SubType('super2'); sub1.arr.push('cc'); console.log(sub1.superProp) // super1 console.log(sub2.superProp) // super2 console.log(sub1.arr); // ["aa", "bb", "cc"] console.log(sub2.arr); // ["aa", "bb"] arr没有被实例共用 console.log(sub1.getArr) // undefined 原型上的属性或方法无法继承
虽然这种方式解决了原型继承出现的问题,但这种方式也是有明显的缺点的。
缺点:由于实现继承没有涉及到原型prototype,所以父类的原型方法自然不会被子类继承。而如果想要实现继承,则必须将方法放在构造函数中,
但这样创建出来的每个实例都会单独拥有一份而不会共用,就会违背代码复用的原则。
三、混合继承
实现:将上述两种方式混合使用,解决上述两种方式出现的问题。
代码示例:
function SuperType(prop) { this.superProp = prop; this.arr = ['aa', 'bb']; }; SuperType.prototype.getArr = function () { console.log(this.arr); }; function SubType(prop) { SuperType.call(this, prop); }; SubType.prototype = new SuperType(); var sub1 = new SubType('super1'); var sub2 = new SubType('super2'); sub1.arr.push('cc'); console.log(sub1.superProp) // super1 console.log(sub2.superProp) // super2 sub1.getArr() // ["aa", "bb", "cc"] sub2.getArr() // ["aa", "bb"]
同样,这种继承方式也是有缺点的,由于在使用构造函数继承时我们执行了一遍父类的构造函数,在原型继承的时候我们又执行了一遍父类的构造函数,
这样就使得父类的构造函数被执行了两遍。看来这也不是最完美的实现继承的方式。
那么,到底存不存在最完美的实现继承的方式呢?
后面会继续补充~~