basyura's blog

あしたになったらほんきだす。

this は呼ばれ方によって 4 種類の違いがある

  • メソッド呼び出しパターン
  • 関数呼び出しパターン
  • コンストラクタ呼び出しパターン
  • apply 呼び出しパターン

このうち、コンストラクタ呼び出しの際の関数呼び出しパターン(?)について。

パブリックメソッドからプライベートなメソッドを呼びたい場合、javascript をあまり知らない java 使いだとこう(↓)書いてしまうと思う。

var msg = 'global hello';
var Test = function() {
  this.msg = 'hello';
  this.say = function() {
    print(this.msg); // => hello
    func_say();
  }
  function func_say() {
    print(this.msg); // => global hello
  }
}
var t = new Test();
t.say();

でもこれ、 func_say() の中の this はグローバル変数を指しているので this.msg は 'global hello' を参照することになる。global な msg が無い場合は undefined になるからなんで?ってなる。
func_say に this をつければメンバ変数にアクセスできるけど、呼び出す側も this をつけないと global な func_say を呼び出してしまう落とし穴。

var msg = 'global hello';
function func_say() {
  print('global func_say');
}
var Test = function() {
  this.msg = 'hello';
  this.say = function() {
    print(this.msg);
    this.func_say(); // => hello
  }
  this.func_say = function() {
    print(this.msg); // => hello
  }
}
var t = new Test();
t.say();

java を書くときには "なるべく private なメソッドからインスタンス変数にアクセスしない" という自分ルールを作っていて、これに従えば

var Test = function() {
  this.msg = 'hello';
  this.say = function() {
    print(this.msg);
    func_say(this.msg);
  }
  function func_say(msg) {
    print(msg);
  }
}
var t = new Test();
t.say();

と書けるので一番ミスが少ないと思う。
やっぱりアクセスしたい場合は魔法を使う。

var Test = function() {
  var that = this; // ★
  this.msg = 'hello';
  this.say = function() {
    print(this.msg);
    func_say();
  }
  function func_say(msg) {
    print(that.msg); // ★
  }
}
var t = new Test();
t.say();

this を that に置き換える。that が一般的らしいけど何を指しているのかよく分からないので self にしてみる。

var Test = function() {
  var self = this;
  this.msg = 'hello';
  this.say = function() {
    print(self.msg);
    func_say();
  }
  function func_say(msg) {
    print(self.msg);
  }
}
var t = new Test();
t.say();

こっちの方が事故が少ないのではないかという考えに至る。
これでも、パブリックメソッドからパブリックメソッドを呼ぶときに slef をつけないと事故る可能性がある。java を書くときはカッコ悪いという理由で書いてないし。

いい方法が無いものか。