みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

JS 親functionのフィールドを参照したい

ボタンをクリックすると、任意の文字がalertで表示されるHTMLを生成するプログラムをJavaScriptで(JQueryを使用しています)書いています。

イメージは、
<button onclick='alert(任意の文字列)'>CLICK ME!</button> のようなHTMLです。

JavaScript部分は以下です。

var ButtonMaker = function(msg){
   this.msg = msg;
}

ButtonMaker.prototype = {
   getButton: function(){
      var button = $('<button>').text('CLICK ME!');
      button.click(this.eventMaker());
      return button;
   },
   
   eventMaker: function(){
      var that = this; // ←これをしたくありません
      return function(){
         alert(that.msg);
      }
   }
}

// 以下のようにして使います

var bmaker = new ButtonMaker('This is a message.');
$(document.body).append(bmaker.getButton());


上記のコードを実行すれば、自分の思い通りの動きになります。ですが、eventMaker()メソッドが気に入りません。var that = thisをしたあと、that.msgなどとして参照しないといけないのが嫌です。

また、以下のコードのようにeventMaker()にmsgを引数に渡すのもあまりしたくありません。なぜなら、実際はButtonMakerのフィールドがもっとたくさんあり、それらのいくつかを参照するからです。

eventMaker2: function(msg){
  return function(){
    alert(msg);
  }
}

よろしくお願いします

投稿日時 - 2014-05-25 11:12:58

QNo.8609922

困ってます

質問者が選んだベストアンサー

質問は「もっとシンプルな eventMaker の実装方法はないか」でよいでしょうか。

これに答えるのであれば、以下を思いつきました:

メソッド定義部分:
eventMaker: function() {
  return function() {
    alert(this.msg);
  }.bind(this);
}

eventMaker メソッドから、ButtonMaker オブジェクトをバインドした無名関数を返す方法です。
無名関数内で this は常に ButtonMaker オブジェクトを指すことになります。


本質的に同じ発想で、次のようにもできます:

コンストラクタ定義部分:
var ButtonMaker = function(msg) {
  this.msg = msg;
  this.event = this.event.bind(this);
}
メソッド定義部分:
event: function() {
  alert(this.msg);
}
getButton: function() {
  …
  button.click(this.event);
  return button;
}

event メソッドに ButtonMaker オブジェクトをバインドしてしまう方法です。
button.click の引数にメソッドの戻り値ではなく、メソッドそのものを渡します。


var that = this;
が気に食わない感覚はわかります。
ですが Function.prototype.bind の IE によるサポートはバージョン 9 からですし、
var self = this;
とする(that より見間違いが減るのでこちらのほうが好みです)のはおかしなことではないと感じます。
保守性の大きな低下を引き起こすのでなければ、慣れだと思ってしまうのが精神衛生上良いことかと思います。


【まとめ】
変数 that を使わないためには Function.prototype.bind を使うとよいでしょう。

投稿日時 - 2014-05-25 11:54:33

お礼

ありがとうございます

bind()というのは知りませんでした。「>本質的に同じ発想で、次のようにもできます:」はより見やすくて良いと思いました。

よくわからないのが、「this.event = this.event.bind(this);」です。右辺のthis.event.bind(this)のthis.eventはメソッドなのでしょうか?そして、その左辺のthis.eventは新しく定義しているですよね?もしかして、eventという識別子が上書きされているのでしょうか?

もしよろしければ、この質問にも回答お願いできませんか?

投稿日時 - 2014-05-25 14:01:22

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(2)

ANo.2

右辺の
 this.event
はオブジェクトのプロトタイプが持つメソッド
 ButtonMaker.prototype.event
を指しています。
 this.event === ButtonMaker.prototype.event
は真です。

一方 左辺は、オブジェクトの実体が持つプロパティ this.event を指しています。
ご指摘のとおり、新たに定義しています。
この式の実行後に
 this.event === ButtonMaker.prototype.event
は偽となります。

上書きと言ってしまうと誤解を生むかもしれません。
「プロトタイプチェーン」という仕組みです。
 bmaker.event
がプロトタイプのプロパティ ButtonMaker.prototype.event ではなく、オブジェクト自体のプロパティを参照するようになるのです。

投稿日時 - 2014-05-25 17:57:02

お礼

メインの質問以外の回答ありがとうございます!

上書きでありませんね。bmaker.eventと参照するとButtonMaker.prototypeを見る前にButtonMakerのフィールドにeventがあるので、そちらが優先して呼び出されるというわけですね。最後までありがとうございました。

投稿日時 - 2014-05-25 19:38:30

あなたにオススメの質問