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は、何を参照していたんだろう。中身を調べてみましたが、よくわかりませんでした。理解しきれてなくてなんか気持ち悪い。

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.