javascriptでオブジェクト内にオブジェクトを作ったらsetTimeout関数のthis問題が複雑化した

javascriptでオブジェクト内にオブジェクトを作ったらsetTimeout関数のthis問題が複雑化した:

前回の続き。

前回の例と違うのは、クラス内からsetTimeoutを呼んでるのと、オブジェクト内のオブジェクトのメソッドを呼んでること。


setTimeout関数の失敗例 その2

<script> 
    document.addEventListener('DOMContentLoaded', function () { 
        'use strict'; 
        class Test { 
            constructor() { this.value = "成功"; } 
            alert() { 
                alert(this.value); 
            } 
        } 
        class TestWrapper { 
            constructor() { 
                this.test = new Test(); //オブジェクト内にオブジェクトを作成 
            } 
            setTimeoutWrap() { 
                setTimeout(this.test.alert.bind(this), 100); //失敗例 
            } 
        } 
 
        const testwrapper = new TestWrapper(); //オブジェクトを作成 
        test01.addEventListener('click', function () { 
            testwrapper.setTimeoutWrap(); 
        }); 
    }); 
</script> 
<button id="test01">test01</button> 
このプログラムを実行すると



undefined.png


undefinedが返ってきた。


成功例

どのように書けばいいかというと、setTimeout(this.test.alert.bind(this.test), 100);と書けば成功。setTimeoutで呼び出すメソッドが連鎖する場合、bindするオブジェクトも連鎖させなければならないようだ。

オブジェクトの4段連鎖なら、setTimeout(this.test.test2.test3.alert.bind(this.test.test2.test3), 100);となる :confounded:

setTimeout(function () { this.test.alert() }.bind(this), 100);と書いても成功。前回書いたように、括弧を付けないとオブジェクトのメソッドが関数化するので、括弧を付けて関数化させないほうがいい。オブジェクトの4段連鎖なら、setTimeout(function () { this.test.test2.test3.alert() }.bind(this), 100);となってbind(this)1つで済むので。


class内メソッドのアロー関数化

アロー関数にすればそれが定義されている場所でのthisになるので、class内メソッドをアロー関数にできないか考えてみた。

<script> 
    document.addEventListener('DOMContentLoaded', function () { 
        'use strict'; 
        class Test { 
            constructor() { 
                this.value = "成功"; 
                this.alert = () => { 
                    alert(this.value); 
                } 
            } 
        } 
        class TestWrapper { 
            constructor() { 
                this.test = new Test(); //オブジェクト内にオブジェクトを作成 
            } 
            setTimeoutWrap() { 
                setTimeout(this.test.alert, 100); //成功 
            } 
        } 
 
        const testwrapper = new TestWrapper(); //オブジェクトを作成 
        test01.addEventListener('click', function () { 
            testwrapper.setTimeoutWrap(); 
        }); 
    }); 
</script> 
<button id="test01">test01</button> 
constructor内にメソッドを書く書き方が美しくないが、これはいいかもしれない :smirk_cat:

オブジェクトは本来こうあるべきじゃあないだろうか。

この書き方でできなくなることもある。呼び出し側で関数にbind(new_this)とやってアロー関数内のthisの値を書き換えられなかった。bind関数よりもアロー関数のほうが強い。

コメント

このブログの人気の投稿

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2021-04-30 23:37:32 RSSフィード2021-04-30 23:00 分まとめ(42件)

投稿時間:2023-02-05 02:09:04 RSSフィード2023-02-05 02:00 分まとめ(9件)