概要
オブジェクトを定義して、その中のメソッドでthisを使うと、想定外(と思ってしまう。勉強不足で)の動き方をしている。
しかし、よく勉強してみると、当然かと思うこともある。
オブジェクトの中のプロパティやメソッドを参照しているつもりが、もっと上のwindowオブジェクトで、ブラウザーのjavascriptエンジンがそれらのプロパティやメソッドを探していたためで、その時はundefinedエラーになる。例えば、メソッドが見つからないとか。なぜ、windowでなく、定義したオブジェクトに探しに行かないのか。この原因について、勉強を重ねた。
サンプル
以下は、そのサンプルです。
まず、TubeListオブジェクトを定義しています。いくつかのpropertyと、メソッドがあります。
//抜粋
let TubeList = {
//プロパティ定義
site_name: "",
aaa:"",
youtube_timer: null,
・・・
//メソッドの中で、thisを使っています。
content_ready (){
・・・
//(注1)抜粋
this.countdown(this.aaa);
・・・
//(注2)抜粋
//再帰コール
this.youtube_timer = setTimeout(this.content_ready.bind(TubeList), 1000);
return;
},
countdown (aaa){
・・・
}
};
//(注3)抜粋
//TubeListオブジェクトの外側で、bind()しています。
//1秒毎にリストを取得
TubeList.youtube_timer = setTimeout(TubeList.content_ready.bind(TubeList), 1000);
・・・
このサンプルは、「なつかしの曲(ポータル)」サイトで使用しているプラグインでyoutubeサーチをするスクリプトの抜粋です。一秒毎にスクロールして動画タグを収集しています。
問題は、このサンプルで、TubeListオブジェクト内でthisを使っているところでundefinedエラーが発生しました。(注3)で対策前は、bind()していませんでした。そのため、setTimeoutでcontent_readyメソッドを呼び出した時のcontent_readyメソッド内で使用しているthisはwindowオブジェクトになっていたためです。
thisはTubeListオブジェクトを参照させるため、.bind(TibeList)を使用しました。そうすると、content_readyメソッド内のthisは想定通り、TubeListオブジェクトを参照してくれました。
参照するスコープが想定外だった。
thisの参照先が定義したオブジェクトでなく、windowオブジェクトだったとわかった時はがっかりする。なぜだろうかと、理解不足の時は困惑していた。様々な記述方法で試してみたが、一向に解決しなかった。
試行錯誤を重ねているうちにある時、何とか動作した。
.bind()を書く書き方である書き方にたどり着き、うまく動作した。
構文の書き方を熟知してなく、手あたり次第に試していて時間がかかった。
仕様を呼んでもすぐには動かない。やはり、泥臭い作業が必要か。
メソッドの親指定は、オブジェクト名かthisか
サンプルで、メソッドを参照する場合、そのオブジェクト名を直接指定しても動作した。TubeList.content_ready()とか、一方、thisを使う方が
なんかスマートな感じがしていたので、何とかthisで動作させようと四苦八苦していた。
どちらが、いいのか。
ソースコードの可読性からはthisはわかりにくい。直接、オブジェクト名を記述した方が可読性はよい。
二つの参照先があると、うっかりすると、windowオブジェクト内に、定義したオブジェクトのプロパティデータを入っていたりする。
以後、そのwindowオブジェクトのプロパティデータで処理が続行していたりする。定義したプロパテイは空データのままだったりする。
バグの温床になりかねないが。どうしたらいいのか、思案中。strictを指定すべきか。
あとがき
オブジェクトのメソッド内でthisを使用するには注意が必要と感じました。setTimeoutやalert,console.logなどのwindowオブジェクト
を使用するときはこの対策が必要になります。他にも、.call()や.apply()メソッドなどあるようですが、まだ試していません。
追記
call() apply()メソッドは、以下のサイトで勉強させていただきました。
このサイトはわかりやすいです。
参考サイト
https://tcd-theme.com/2021/12/javascript-call-apply.html