JavaScriptのthisのスコープでの嵌り
Starbug1の日付入力支援用にJavaScriptのカレンダーを、車輪していました。(80%は道楽のため)どこかでthisのスコープについての注意点を何回か読んだ気がするのですが、自分で嵌ってみないと本当には理解できなかった。
カレンダークラスは長くなるので、黒く塗れクラスで嵌った内容を説明します。黒く塗れクラスは、divタグで囲まれたブロックをクリックした時に、divタグの背景色を黒くするクラスです。コンストラクタの引数で黒くするブロックのIDを指定します。
prototype.jsを使ってます。
<html> <head> <script type="text/javascript" src="prototype.js"></script> <script> var PaintItBlack = Class.create(); Object.extend(PaintItBlack.prototype, { target: undefined, initialize: function(target) { // (1) 仮引数の target this.target = $(target); // (2) クラスフィールドの target var target_var = this.target; // (3) varで宣言したtarget_var //Event Event.observe(this.target, 'click', function(){ // (4) //this.target.style.backgroundColor = 'black'; // (5) target_var.style.backgroundColor = 'black'; // (6) $(target).style.backgroundColor = 'black'; // (7) } ); } }); Event.observe(window, "load", function() { var black = new PaintItBlack('block1'); }); </script> </head> <body> <div id="block1">ROLLING STONES</div> </body> </html>
(4)の関数では、クリック時のイベントを定義しています。
(5) this.target
最初は、(5)でthis.targetとして、PaintItBlackクラスのフィールドに保存していたthis.targetオブジェクトに対して背景を黒くしようとしていましたが、(5)で参照するthisは別物になってしまっているようでした。そのため、実行時にエラーになってしまっていました。this.targetが、(4)実行時のレキシカル環境内に存在すると思っていたことが敗因。
(6) target_var
一度、varで新しい変数を作って、this.targetを退避させてあげると、コンストラクタで指定したIDのブロックの背景を変更することができました。var宣言した変数は、普通にレキシカル環境内に含まれました。
(7) コンストラクタの仮引数
prototype.jsの$関数で、コンストラクタの仮引数を直に参照してしまっても、コンストラクタで指定したIDのブロックの背景を変更することができました。上位の関数の仮引数も、レキシカル環境内に含まれました。
ということは、
JavaScriptのスコープにおいて、thisは特別扱いする。thisは、レキシカルスコープに含まれない。(5)のthisは、何を参照していたんだろう。中身を調べてみましたが、よくわかりませんでした。理解しきれてなくてなんか気持ち悪い。