const hoge = { ...hoge }はシャローコピーだと思ってたけどシャローコピーじゃなかった

**多分コメント欄が本番です**

バカみたいな話ですが、今まで、

``` .ts
const hoge = { ...hoge }
```

みたいなコードを書いてシャローコピーしたつもりになってたんですが、全然そんなことなかったって話です。黒歴史だ・・・

例えば、以下のようなクラスAを作ったとして、

```.ts
class A {
    constructor() {
        this.aaa = 'aaa';
        this.bbb = {
            ccc: 'ccc'
        };
    }
    afunc() {
        console.log('クラスAの関数だよ');
    }
    get aGetter() {
        return this.aaa;
    }
}
```

そのインスタンスを以下のように作り、スプレッド演算子でシャローコピー（のつもり）を取ると、

```.ts
const a = new A()
const _a = { ...a }
```

`_a.aaa` や `_b.bbb.ccc` にはアクセスできるんですが、`_a.afunc()` や `_a.aGetter` にはアクセスできません。

また、`instanceof` の結果も変わります。

```.ts
// Aクラスのインスタンスかどうか
console.log(a instanceof A) // => true
console.log(_a instanceof A) // => false
```

空オブジェクトにプロパティを詰め直しているイメージだと思うので、 `instanceof` が変わるのはまあそうだよねって感じですが、メソッドやGetterも取れなくなるのはちょっと予想外でした。

と思ったら以下のコードは動くんですよね

``` .js
const c = {
  d() {
    console.log('d')
  },
}

const _c = { ...c }

_c.d() // => メソッドだけどアクセスできる！！
```

オブジェクトリテラルだといけるのかよどういうことなんだ・・・

ReactのpropやStore周りを書いていると、スプレッド演算子を使ったこんな感じのコードをよく書いているので、気をつけたいです。

## シャローコピーを取る方法

以下のように書くとちゃんとシャローコピーを取れるっぽいです。 `instanceof` の結果も`true`になります

``` .js
const _a = Object.assign(Object.create(Object.getPrototypeOf(a)),a)
```

##### 2019/10/12 追記 
コメントで教えていただきましたが、`__proto__` にアクセスするのが良いかはおいておいて、以下でもいけるっぽいです。

``` .js
const _a = { ...a, __proto__: a.__proto__ }
```

以上。

---

以下は検証コードです。暇な人はコピペして実行してみてください

``` .ts
"use strict";
class A {
    constructor() {
        this.aaa = 'aaa';
        this.bbb = {
            ccc: 'ccc'
        };
    }
    afunc() {
        console.log('クラスAの関数だよ');
    }
    get aGetter() {
        return this.aaa;
    }
}

class B extends A {
    constructor() {
        super(...arguments);
        this.ddd = 'ddd';
        this.eee = {
            fff: 'fff'
        };
    }
    bfunc() {
        console.log('クラスBの関数だよ');
    }
    get bGetter() {
        return this.ddd;
    }
}

const b = new B();
const _b = { ...b };
const __b = { ...Object.create(Object.getPrototypeOf(b)), ...b };
const ___b = Object.assign(Object.create(Object.getPrototypeOf(b)), b);

console.log(b);
console.log(_b);
console.log(__b);
console.log(___b);

// Bクラスのインスタンスかどうか
console.log(b instanceof B); // => true
console.log(_b instanceof B); // => false
console.log(__b instanceof B); // => false
console.log(___b instanceof B); // => true

// Aクラスのインスタンスかどうか
console.log(b instanceof A); // => true
console.log(_b instanceof A); // => false
console.log(__b instanceof A); // => false
console.log(___b instanceof A); // => true

// Bクラスメソッドへのアクセス
console.log(b.bfunc); // => 返ってくる
console.log(_b.bfunc); // => undefined
console.log(__b.bfunc); // => undefined
console.log(___b.bfunc); // => 返ってくる

// Aクラスメソッドへのアクセス
console.log(b.afunc); // => 返ってくる
console.log(_b.afunc); // => undefined
console.log(__b.afunc); // => undefined
console.log(___b.afunc); // => 返ってくる

// Bクラスのgetプロパティへのアクセス
console.log(b.bGetter); // => ddd
console.log(_b.bGetter); // => undefined
console.log(__b.bGetter); // => undefined
console.log(___b.bGetter); // => ddd

// Aクラスのgetプロパティへのアクセス
console.log(b.aGetter); // => aaa
console.log(_b.aGetter); // => undefined
console.log(__b.aGetter); // => undefined
console.log(___b.aGetter); // => aaa

```