無名関数実行時のthisの中身

John Resig本でjavascriptを勉強中。掲載されているサンプルを動かしてみたが、うまく動かなかったので実行コンテキストについて調べてみた.

入れ子の無名関数が参照するthisって何?

以下のコードがうまく動かなかった。(掲載されているコードをちょっと省略)

function User(params) {
  for(i in params) { (function() {
    this['get' + i] = function() {
      return params[i];
    }
  })(); }
}

var user = new User({
  name: 'snaka',
  age: 35
});

alert(user.getname());

"TypeError: user.getname is not a function"と言われてしまう。どうも、this['get' + i] = ... のところで参照している this が User のインスタンスでは無いっぽい。

調べてみた

じゃ、何なのか?と alert(this) してみたら、Windowオブジェクトを指している。

thisについて調べてみた。以下無名関数の「実行コンテキスト」に関する記述の抜粋。

Finally a value is assigned for use with the this keyword. If the value assigned refers to an object then property accessors prefixed with the this keyword reference properties of that object. If the value assigned (internally) is null then the this keyword will refer to the global object.

Javascript Closures

と、ある。まとめると...

  • hoge.func() という感じで呼び出された場合、 func() の中での this は hoge オブジェクトを指す。
  • func() という感じで(プレフィクス無しで)呼び出された場合は、 func() の中での this はグローバルオブジェクト(ブラウザ環境ではwindowオブジェクト)を指す。

ということらしい。

修正してみる

調べた結果から、最初のコードを修正してみる。
無名関数の実行時にプレフィクスを指定することはできないので、その代わりとして、(function(){... }).call(this) という記述に変えてみた。

function User(params) {
  for(var i in params) {(function() {
    this['get' + i] = function() {
      return params[i];
    }
  }).call(this); }
}

var user = new User({
  name: 'snaka',
  age: 35
});

alert(user.getname());

と、やればうまくいく... と思ったけど、user.getname() の戻り値にage の値が返ってくる。以下のように直す。

function User(params) {
  for(var i in params) {(function() {
    var propName = i;
    this['get' + propName] = function() {
      return params[propName];
    }
  }).call(this); }
}

var user = new User({
  name: 'snaka',
  age: 35
});

alert(user.getname());

無名関数のスコープにpropNameという変数を用意して、それに無名関数実行時点の i の参照を保持するようにした。

これでOK