1386553018 Javascript でクラス内のメゾッドを呼び出させるにはどうすればよいのでしょうか?


Javascriptを勉強を始めて数日の者です。
自分なりの作り方の勉強中です。
ポップアップのサンプルを作成集なのですが、いまいち、クラス的なメゾッドの呼び出し方と、変数のスコープ範囲がわかっていない状態です。
下記のようなソースを作って、テストを行っております。

下に記載したようなソースで、
①※1、※2のコメントを外すと、ポップアップが表示されません。
 クラス内のメゾッドを div と等から呼び出させることは出来ないのでしょうか?
 (サンプルの様な記載をすると、OnCancel が呼び出されてしまい、表示=>閉じる で操作してしまう為 クロームのステップ実行で確認)

②①で呼び出せる方法があったとして、※3の様にクラス内の変数を参照することは出来るのでしょうか

Javascriptにお詳しい方ご指導ください。

ソースは文字数制限で入力できなかったので、画像で張り付けています。

回答の条件
  • 1人5回まで
  • 13歳以上
  • 登録:2013/12/09 10:36:58
  • 終了:2013/12/11 17:04:02
id:kameoyaji_2


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<title>PopUp</title>
<script type="text/javascript">
//<![CDATA[
function PopUpTest() {
var _PopUpTest = new ClsPopUpTest();

}

function ClsPopUpTest() {

this._Iframe = null;
this._Document = null;

// テンキー表示用の iframe を作成する。
this._Iframe = document.createElement( "iframe");

// ドキュメントに追加
window.document.body.appendChild( this._Iframe );

// iframeのドキュメントをプロパティに保存
this._Document = this._Iframe.contentDocument;

// iframeのスタイルを設定する。

this.tiframestyleset();

}

ClsPopUpTest.prototype =
{

// iframeのスタイルシートを作成する。
tiframestyleset : function(){
this._Iframe.style.width = '100px';
this._Iframe.style.height = '200px';
this._Iframe.style.left = '10px';
this._Iframe.style.top = '10px';
this._Iframe.style.border = '1px solid #999999';
this._Iframe.style.padding = '0px';
this._Iframe.style.backgroundColor= '#EEEEEE'; // 背景色
this._Iframe.style.position = 'absolute';

this._Iframe.style.display = 'block';
this._Iframe.style.zIndex = 100;

// クリックしたら終了させる。
// this._Document.body.onmousedown = this.OnCancel(); // <=※1

// 閉じるボタンを作成する。
var closebtn = this.BtnCreate(this._Document.body, "閉じる");

// 閉じるボタンを追加する。
this._Document.body.appendChild(closebtn);

},
// <div>を使用したボタンを作成する。
BtnCreate:function ( ele , val ){

var btn = this._Document.createElement("div");
var textn = this._Document.createTextNode(val);
btn.appendChild(textn);
// btn.onclick = this.OnCancel(); // <=※2
ele.appendChild(btn);
return btn;
},

//**********************************
// イベント系の処理はこの下に記載
//**********************************

// キャンセル処理(ポップアップを閉じるだけ) ※3
OnCancel : function(){
if (this._Iframe){
window.document.body.removeChild(this._Iframe);
}
},

//**********************************
// イベント系の処理はこの下に記載
// 最後にこれを配置して、 途中は
// すべて }, で記載する。
//**********************************
// 解放処理、必要に応じて記載する。
dispose : function() {
}
}

//>
</script>
</head>
<body>
<input type='button' value='ポップアップ' onclick='PopUpTest();' />
</body>
</html>

ベストアンサー

id:tukihatu No.2

牛乳先生(tukihatu)回答回数180ベストアンサー獲得回数322013/12/09 17:36:35

ポイント70pt

既に回答出てましたが、ソース作成したので詳しく書きます。長いけど。
結論から書くと「できるけど、iframeでやるには、クラスとか関係なく難しすぎる。」ということです。

・記述ミスについて
onmousedownやonclickはイベントなので、戻り値は関数になります。ごっちゃになるのは仕方ないですが覚えるしかありません。

this._Document.body.onmousedown = this.OnCancel();
↓これは下の式とイコールなので関数にならずに命令が実行される
this._Document.body.onmousedown = if (this._Iframe){
window.document.body.removeChild(this._Iframe);
}

this._Document.body.onmousedown = this.OnCancel;
↓これは下の式とイコール。期待通りに動く
this._Document.body.onmousedown = function(){
	if (this._Iframe){
		window.document.body.removeChild(this._Iframe);
	}
}

しかし、このように文を変えても、もう一つの問題があるため動きません。
(もしかしたらこちらは知っているかもしれませんが)

・thisの参照値が変わる
上の対応で文法は正しくなりましたが、thisの参照値が変わってしまいます。

this._Document.body.onmousedown = this.OnCancel;
OnCancel : function(){
	if (this._Iframe){//→ここでのthisは「this._Document.body」を参照する
		window.document.body.removeChild(this._Iframe);
	}
}

よってthis._Document.body._Iframeを探しに行っていることになる

this._Document.bodyからのonmousedownイベントになるので、そこからの参照値になります。
よってthisは使えません。
また、iframe内からの参照になるので、親フレームにあるクラスClsPopUpTestにもアクセスが難しいです。(divじゃだめなんですかね?)
変数のroot化をしても厳しそうですし、root化はやりたくないような人もいるので…


一番楽だと思われるのが、イベント関数に引数を渡してやることなのですが、通常では引数を渡せません。(イベント関数の引数にはクリックしたときの状況などが入ってくるため)
最初の話に戻る形になります。

this._Document.body.onmousedown = this.OnCancel(this._Iframe);
→戻り値が関数ではなくなるので挙動がおかしい

引数を渡すには無名関数を使った方法がありますのでこちらでどうぞ。

this._Document.body.onmousedown = (function(d){→引数d(適当)には最後に書いてある括弧内の要素が入る
	return function(e){→onmousedownにちゃんと関数を返してあげる。eにはクリック時の状況データが入る。省略可能
		d.OnCancel(d._Iframe);→thisではなく引数dにする
	}
})(this);→このthisが引数dに入る

■部分ソース
二つを改修したのがこちらです。

		// クリックしたら終了させる。
		this._Document.body.onmousedown = (function(d){
			return function(){
				d.OnCancel(d._Iframe);
			}
		})(this);
	// <div>を使用したボタンを作成する。
	BtnCreate:function ( ele , val ){
		var btn = this._Document.createElement("div");
		var textn = this._Document.createTextNode(val);
		btn.appendChild(textn);
		btn.onclick = (function(d){
			return function(){
				d.OnCancel(d._Iframe);
			}
		})(this);  // <=※2
		ele.appendChild(btn);
		return btn;
	},
	// キャンセル処理(ポップアップを閉じるだけ)  ※3
	OnCancel : function(obj){
		if (obj){
			window.document.body.removeChild(obj);
		}
	},

※chromeでしか見てませんが動くと思います。

とまあややこしいお話でした。

引数の話
http://d.hatena.ne.jp/hi_c_mayu/20090704/1246641410

その他の回答(1件)

id:language_and_engineering No.1

lang_and_engine回答回数170ベストアンサー獲得回数632013/12/09 16:44:57スマートフォンから投稿

ポイント30pt

http://javascriptmania.blog111.fc2.com/blog-entry-26.html

2箇所とも、ここに記載されている点でミスをしています。
イベントリスナを代入でセットする際には、関数オブジェクトそのものを代入するから、カッコをつけてはいけません。
カッコをつけてしまうと、その時点で関数OnCancelが実行されます。それで質問文のような挙動になります。

id:tukihatu No.2

牛乳先生(tukihatu)回答回数180ベストアンサー獲得回数322013/12/09 17:36:35ここでベストアンサー

ポイント70pt

既に回答出てましたが、ソース作成したので詳しく書きます。長いけど。
結論から書くと「できるけど、iframeでやるには、クラスとか関係なく難しすぎる。」ということです。

・記述ミスについて
onmousedownやonclickはイベントなので、戻り値は関数になります。ごっちゃになるのは仕方ないですが覚えるしかありません。

this._Document.body.onmousedown = this.OnCancel();
↓これは下の式とイコールなので関数にならずに命令が実行される
this._Document.body.onmousedown = if (this._Iframe){
window.document.body.removeChild(this._Iframe);
}

this._Document.body.onmousedown = this.OnCancel;
↓これは下の式とイコール。期待通りに動く
this._Document.body.onmousedown = function(){
	if (this._Iframe){
		window.document.body.removeChild(this._Iframe);
	}
}

しかし、このように文を変えても、もう一つの問題があるため動きません。
(もしかしたらこちらは知っているかもしれませんが)

・thisの参照値が変わる
上の対応で文法は正しくなりましたが、thisの参照値が変わってしまいます。

this._Document.body.onmousedown = this.OnCancel;
OnCancel : function(){
	if (this._Iframe){//→ここでのthisは「this._Document.body」を参照する
		window.document.body.removeChild(this._Iframe);
	}
}

よってthis._Document.body._Iframeを探しに行っていることになる

this._Document.bodyからのonmousedownイベントになるので、そこからの参照値になります。
よってthisは使えません。
また、iframe内からの参照になるので、親フレームにあるクラスClsPopUpTestにもアクセスが難しいです。(divじゃだめなんですかね?)
変数のroot化をしても厳しそうですし、root化はやりたくないような人もいるので…


一番楽だと思われるのが、イベント関数に引数を渡してやることなのですが、通常では引数を渡せません。(イベント関数の引数にはクリックしたときの状況などが入ってくるため)
最初の話に戻る形になります。

this._Document.body.onmousedown = this.OnCancel(this._Iframe);
→戻り値が関数ではなくなるので挙動がおかしい

引数を渡すには無名関数を使った方法がありますのでこちらでどうぞ。

this._Document.body.onmousedown = (function(d){→引数d(適当)には最後に書いてある括弧内の要素が入る
	return function(e){→onmousedownにちゃんと関数を返してあげる。eにはクリック時の状況データが入る。省略可能
		d.OnCancel(d._Iframe);→thisではなく引数dにする
	}
})(this);→このthisが引数dに入る

■部分ソース
二つを改修したのがこちらです。

		// クリックしたら終了させる。
		this._Document.body.onmousedown = (function(d){
			return function(){
				d.OnCancel(d._Iframe);
			}
		})(this);
	// <div>を使用したボタンを作成する。
	BtnCreate:function ( ele , val ){
		var btn = this._Document.createElement("div");
		var textn = this._Document.createTextNode(val);
		btn.appendChild(textn);
		btn.onclick = (function(d){
			return function(){
				d.OnCancel(d._Iframe);
			}
		})(this);  // <=※2
		ele.appendChild(btn);
		return btn;
	},
	// キャンセル処理(ポップアップを閉じるだけ)  ※3
	OnCancel : function(obj){
		if (obj){
			window.document.body.removeChild(obj);
		}
	},

※chromeでしか見てませんが動くと思います。

とまあややこしいお話でした。

引数の話
http://d.hatena.ne.jp/hi_c_mayu/20090704/1246641410

id:kameoyaji_2

いろいろありがとうございます。

無名関数のアイデア、頂戴いたします。
サンプルソースまで、作成していただきありがとうございます。

vb的な発想で考えてしまうので間違いが多くなってしまいます。(vbであんまり無名関数を使わない癖があるもので)


なかなか、Javascriptも難しいですね。

頑張って勉強していきます。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません