setTimeout関数の失敗例
<script src="jquery-3.3.1.min.js"></script><!-- jQueryをロード -->
<script>
$(function(){
'use strict';
class Test{
constructor(){this.v="成功";}
alert(){
alert(this.v);
}
}
const t=new Test(); //オブジェクトを作成
$(test01).click(function(e){
setTimeout(t.alert, 100);//失敗例
});
});
</script>
<button id="test01">test01</button>
このプログラムを実行すると
undefinedが返ってきた。1
原因はthis問題
setTimeout() にメソッドを渡すとき、コードが実行される際の this の値が想定とは異なるかもしれません。
setTimeout() によって実行されるコードは、setTimeout が呼び出された関数とは別の実行コンテキスト内から呼び出されます。呼び出された関数に this キーワードを設定する通常の規則を適用して、呼び出しあるいは bind で this を設定しなければ、非 strict モードでは global (または window)、strict モードでは undefined になります。
注記: setTimeout コールバックの既定の this の値は、strict モードであっても undefined ではなく、window オブジェクトです。
出典: MDN Web Docs WindowOrWorkerGlobalScope.setTimeout() "this" 問題
試したら非 strict モードでも strict モード2でも setTimeout コールバックの既定の this の値は、 window オブジェクトだった。 setTimeout(callback)
は内部で callback.call(window)
を呼んでるようだ。
javascriptのオブジェクトの挙動が怪しい!
どのように書けばいいかというと、setTimeout(function(){t.alert()}, 100)
と書けば成功。
t.alert
なら関数扱いでt.alert()
ならオブジェクトのメソッド扱いになるようだ。括弧があるかないかの違いで挙動が変わる。
fun=t.alert; fun();
とやればt.alert
内のthis
の値がundefined
になった。
t.alert
がオブジェクトのメソッドなので明示的に書かなくてもfun=t.alert; fun.call(t)
を呼べばいいのに。
setTimeout(t.alert.bind(t), 100)
と書いてもsetTimeout(function(){t.alert.call(t)}, 100)
と書いてもsetTimeout($.proxy(t.alert,t), 100)
と書いても成功。
t.alert.bind(t)
や$.proxy(t.alert,t)
の内部を見てないがfunction(){t.alert.call(t)}
を返す動きをしてるようだ。
怪しいとはいえ、javascriptのオブジェクトは便利。thisの値3を気にしながらオブジェクトを使えばいい。