---
# System prepended metadata

title: JavaScript Constructor Inheritance Issue
tags: [教學]

---

# JavaScript Constructor Inheritance Issue
> 此篇會以 TypeScript 為輔

## 子類別回傳的不是自己
```typescript
let child = new Child(); // Child 繼承自 Array
console.log(child instanceof Child); // false
```

---
## 一般情況 (普遍預期的結果)
### 首先建立一個 Father Class 
```typescript
class Father { constructor() {} }
```

### 建立一個 Child Class 繼承自 Father
```typescript
class Child extends Father { constructor() {} }
```

### 建立測試
```typescript
let child = new Child();
console.log(child instanceof Child); // true
console.log(child instanceof Father); // true
```
目前都很合理，Child 繼承自 Father，所以既是 Father 也是 Child
那為什麼繼承自 Array 的子類別卻不是如此？

---
### Array 有什麼特別的？
<font color=#FF0000>**若建構子回傳 non-null-reference，
則 new Constructor 會拿到建構子回傳對象，而不是創建對象**</font>

往 Array 底層追，可以看到建構子回傳的不是 Array 本人，而是額外 new 的一個對象 
![](https://i.imgur.com/2rT9nKM.png)

因此，繼承自 Array 的子類別(如下)，拿到的不是創建對象，而是建構子回傳的對象 
```typescript=
// TypeScript
let child = new Child(); // Child 繼承自 Array
console.log(child instanceof Child); // false
```
```javascript=
// JavaScript
var Child = (function (_super) {
    __extends(Child, _super);
    function Child(type) {
        var _this = _super.call(this) || this;
        return _this; // ---> 注意：這裡回傳的是父類別(Array)建構子的結果
    }
    return Child;
}(Array));
```

### 怎麼避免上述情況？我就是想拿到創建對象本人
在父類別回傳非本人時，在子類別特別指定要回傳自己(如下)
```typescript=
// TypeScript
class Child extends Father { 
    constructor() {
        var t = eval(this); 
        // 這裡需要 catch this，不能直接 return this
        // 請讀者查看若直接回傳 this，compile 後的 JavaScript 回傳的是什麼
        return t;
    } 
}
```
```javascript=
// JavaScript
var Child = (function (_super) {
    __extends(Child, _super);
    function Child(type) {
        var _this = _super.call(this) || this;
        var t = eval("this");
        return t; // ---> 注意：這裡回傳的是 Child 本人
    }
    return Child;
}(Array));
```
[點我看 eval 用途](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/eval)

### 測驗
```typescript
class Father { 
    constructor() {
        return new GrandFather();
    } 
}
```
```typescript
class Child extends Father { constructor() {} }
```
```typescript
let child = new Child();
console.log(child instanceof Child); // ？
console.log(child instanceof Father); // ？
console.log(child instanceof GrandFather); // ？
```

#### 相關連結
[參考資料](https://stackoverflow.com/questions/37329977/es6-constructor-returns-instance-of-base-class)

###### tags: `教學`