JavaScript继承:从原型链到组合继承深度解析

0 下载量 34 浏览量 更新于2024-08-30 收藏 95KB PDF 举报
"本文主要探讨JavaScript中的继承机制,特别是基于原型链的继承方式,并逐步引入组合继承的概念。文章首先展示了如何通过将父类实例赋值给子类的原型对象来实现继承,然后讨论了这种继承方式的局限性,即无法继承父类的属性。接着,文章进一步讲解了通过父类的原型对象赋值给子类原型对象的方式,虽然能继承方法,但不能继承属性。最后,文章暗示将这两种方式结合,即组合继承,是解决这一问题的有效策略。" 在JavaScript中,原型链是实现继承的关键机制。原型链是通过对象的`__proto__`属性或`Object.getPrototypeOf()`方法建立的,它允许对象间共享属性和方法。当尝试访问一个对象的属性时,如果该对象本身没有该属性,JavaScript会向上遍历其原型链,直到找到该属性或到达原型链的顶端(通常是`null`)。 在给定的例子中,我们创建了一个`Person`类,它有一个`userName`属性和一个`showUserName`方法。接着,我们创建了一个`Teacher`类,并将`Person`的一个实例赋值给`Teacher.prototype`。这样,`Teacher`的实例`oT`就可以通过原型链访问到`Person`的属性和方法: ```javascript function Person() { this.userName = 'ghostwu'; } Person.prototype.showUserName = function() { return this.userName; } function Teacher() {} Teacher.prototype = new Person(); var oT = new Teacher(); console.log(oT.userName); // ghostwu console.log(oT.showUserName()); // ghostwu ``` 在`oT.showUserName()`执行时,JavaScript首先在`oT`对象上查找`showUserName`方法,未找到后,继续查找`oT`的原型`Teacher.prototype`,依然未找到,于是继续查找`Teacher.prototype`的原型`Person.prototype`,在这里找到了`showUserName`方法,所以返回`ghostwu`。 然而,如果`Person`类有其他实例属性,如`age`,`Teacher`的实例将无法直接访问这些属性,因为它们存在于`Person`的实例而非`Person.prototype`上。为了解决这个问题,可以将`Person.prototype`直接赋值给`Teacher.prototype`,但这会导致丢失`constructor`属性的指向,且不能继承实例属性: ```javascript function Teacher() {} Teacher.prototype = Person.prototype; // 修复constructor指向 Teacher.prototype.constructor = Teacher; ``` 为了兼顾继承实例属性和方法,通常采用组合继承,即将`Person`的实例赋给`Teacher.prototype`以继承实例属性,同时将`Person.prototype`赋给`Teacher.prototype`以继承方法: ```javascript function Teacher() {} Teacher.prototype = Object.create(Person.prototype); Teacher.prototype.constructor = Teacher; var oT = new Teacher(); console.log(oT.showUserName()); // ghostwu ``` `Object.create()`函数在这里起到了创建新对象并设定其原型的作用,使得`Teacher.prototype`继承了`Person.prototype`的所有属性和方法,同时保留了`Teacher`的`constructor`指向。 理解JavaScript的原型链和继承机制是成为JS高手的重要一步。通过原型链实现的继承具有灵活性,但也有其局限性,而组合继承则是目前常用的解决办法,它结合了两种继承方式的优点,能够有效地实现对父类属性和方法的全面继承。