javascript教程之不完整的继承(js原型链)


在JavaScript中,原型链是实现继承的一种主要方式。但是,如果不正确地使用或理解原型链,就可能导致继承不完整或出现一些意料之外的行为。下面,我将简要介绍JavaScript中基于原型的继承机制,并讨论可能导致继承不完整的一些常见问题。

### JavaScript的原型链

在JavaScript中,每个对象都有一个内部的`[[Prototype]]`(也称为`__proto__`,但请注意`__proto__`是一个非标准属性,仅在大多数现代浏览器环境中可用,并不推荐在生产代码中使用)链接,它指向另一个对象。这个链接就构成了原型链。当我们尝试访问一个对象的属性时,如果该对象本身没有这个属性,JavaScript就会沿着原型链向上查找,直到找到该属性或到达原型链的顶端(`null`)。

### 继承的实现

基于原型链的继承通常涉及以下几个步骤:

1. **创建一个新的对象**:这个新对象将作为子类的实例。

2. **设置原型**:将新对象的`[[Prototype]]`链接到父类的一个实例(或父类的原型对象,取决于具体实现)。

### 可能导致继承不完整的问题

1. **忘记设置原型**:

如果忘记将子类的`[[Prototype]]`链接到父类的实例或原型,子类将无法继承父类的属性和方法。


   function Parent() {
       this.name = 'Parent';
   }

   function Child() {
       this.age = 10;
   }
   // 忘记设置 Child.prototype = new Parent();

   var child = new Child();
   console.log(child.name); // undefined,因为没有继承
   

2. **覆盖原型**:

如果在子类中直接修改了`prototype`对象,而没有正确设置原型链,可能会导致丢失继承的属性和方法。


   function Parent() {
       this.name = 'Parent';
   }

   function Child() {
       this.age = 10;
   }

   Child.prototype = {
       greet: function() {
           console.log('Hello');
       }
   };
   // 忘记 Child.prototype = new Parent();

   var child = new Child();
   console.log(child.name); // undefined
   

3. **使用`Object.create`时未正确设置原型**:

`Object.create`方法允许你指定新创建对象的原型对象。如果未正确设置,也会导致继承不完整。


   function Parent() {
       this.name = 'Parent';
   }

   var child = Object.create(null); // 原型被设置为null,不是Parent的实例
   child.age = 10;
   console.log(child.name); // undefined
   

### 正确的继承示例


function Parent() {
    this.name = 'Parent';
}

function Child() {
    this.age = 10;
}

// 正确的原型设置
Child.prototype = new Parent();
Child.prototype.constructor = Child; // 修复constructor指向

var child = new Child();
console.log(child.name); // 'Parent',继承自Parent
console.log(child.age); // 10,Child自己的属性

在上面的例子中,我们通过将`Child.prototype`设置为`Parent`的一个实例来确保`Child`能够继承`Parent`的属性和方法。同时,我们也修复了`constructor`属性的指向,以确保它正确地指向`Child`构造函数。