# 寄生组合

寄生组合式继承是寄生式继承和构造函数继承的组合。但是这里寄生式继承有些特殊，这里他处理不是对象，而是类的原型。

```javascript
// inheriteObject 其实就是Object.create的实现
function inheritObject(o) {
  //声明一个过渡对象
  function F() { }
  //过渡对象的原型继承父对象
  F.prototype = o;
  //返回过渡对象的实例，该对象的原型继承了父对象
  return new F();
}

function inheritPrototype(subClass,superClass) {
    // 复制一份父类的原型副本到变量中
  var p = inheritObject(superClass.prototype);
  // 修正因为重写子类的原型导致子类的constructor属性被修改
  p.constructor = subClass;
  // 设置子类原型
  subClass.prototype = p;
}
```

![寄生组合继承图示](https://3490195898-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LnQxDcxCKODvYvTUWe3%2F-LxzEUj9Wz8f3Ooc52JZ%2F-LxzEz29IuA_oJHqjjLg%2Fimage.png?alt=media\&token=0e633a2e-edba-416f-879d-2c838f6ea0eb)

**我们需要继承的仅仅是父类的原型，不用去调用父类的构造函数**。换句话说，在构造函数继承中，我们已经调用了父类的构造函数。因此我们需要的就是父类的原型对象的一个副本，而这个副本我们可以通过原型继承拿到，但是这么直接赋值给子类会有问题，因为对父类原型对象复制得到的复制对象p中的`constructor`属性指向的不是`subClass`子类对象，因此在寄生式继承中要对复制对象p做一次增强，修复起`constructor`属性指向性不正确的问题，最后将得到的复制对象p赋值给子类原型，这样子类的原型就继承了父类的原型并且没有执行父类的构造函数。

综上，寄生组合只调用了一次超类构造函数，效率更高。避免在`SuberType.prototype`上面创建不必要的、多余的属性，与其同时，原型链还能保持不变。

有一点你需要注意，就是子类在想添加原型方法必须通过prototype来添加，否则直接赋予对象就会覆盖从父类原型继承的对象了.

```javascript
function SuperClass(name) {
  this.name = name;
  this.books=['js book','css book'];
}
SuperClass.prototype.getName = function() {
  console.log(this.name);
}
function SubClass(name,time) {
  SuperClass.call(this,name);
  this.time = time;
}
inheritPrototype(SubClass,SuperClass);
SubClass.prototype.getTime = function() {
  console.log(this.time);
}
var instance1 = new SubClass('React','2017/11/11')
var instance2 = new SubClass('Js','2018/22/33');

instance1.books.push('test book');

console.log(instance1.books,instance2.books);
instance1.getName();
instance2.getTime();
```

{% tabs %}
{% tab title="First Tab" %}

{% endtab %}

{% tab title="输出" %}
instance1.books: \["js book", "css book", "test book"]

instance2.books: \["js book", "css book"]

instance1.getName(): 2017/11/11

instance2.getName(): 2018/22/33
{% endtab %}
{% endtabs %}

> 修正constructor是为了保证它能按照constructor被设计的意义一样正确的指向构造函数，如果constructor正确指向构造函数，就意味着能获取到构造函数的prototype，拿到prototype，哈哈那你就可以为所欲为了，但是又因为constructor的指向不是强制的，所以如果你想要用constructor做什么事要小心，因为它一不定都是严格指向该对象的构造函数，所以这边你修改不修改没有什么强制性
>
> constructor属性**不影响**任何JavaScript的内部属性。instanceof检测对象的原型链，通常你是无法修改的（不过某些引擎通过私有的\_\_proto\_\_属性暴露出来）。
>
> constructor其实没有什么用处，只是JavaScript语言设计的历史遗留物。由于constructor属性是可以变更的，所以未必真的指向对象的构造函数，只是一个提示。不过，从编程习惯上，我们应该尽量让对象的constructor指向其构造函数，以维持这个惯例。\
> \
> 作者：贺师俊\
> 链接：<https://www.zhihu.com/question/19951896/answer/13457869\\>
> 来源：知乎\
> 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://mm.ricky.moe/javascript/js-concept/ji-cheng/ji-sheng-zu-he.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
