【WSH事始め】JavaScriptでのカプセル化をクロージャという

はじめに

 正直 説明いらんかなぁと思っていたのですが、そもそもJScript でJavaScript とオブジェクト指向学習してしまおうという当ブログの真の目論見があり、継承と名前空間出してしまった以上、これに触れざるを得ないかと思ったので 取り上げました。(ということはポリモーフィズムもやらねばならんのか?)

 いつも通り解説は他所様へ丸投げなので【前提知識】シリーズに追加、

 ・・・していたのですが、グローバルな名前空間についての記事を用意していたところ、参考サイトの消失と共に若干の勘違いに気づきまして、整理の上、当記事へコーディング比較を追記することにしましたので【WSH事始め】へ昇格としました。

要するに 保護したい変数と setter とgetter を同じ関数内に閉じ込めるコト

 一言でまとめるなら サブタイトルの通り。

 どうなるかと云うと、変数のスコープが閉じ込めた関数ブロック内に収まるということです。

 尚、setter とgetter はタダの関数です。引数が有るか無いかの違いです。引数が有れば置き換えた値を、引数が無ければ現在の値を返します。

 詳細は丸投げしたリンク先で確認してください。

説明丸投げの外部リンク

 サンプルソースをWSHで動かす上での注意点 。 

 拡張子 js のテキストファイルに サンプルをコピペして、以下の修正を行うことで エクスプローラ上からダブルクリックで実行できます。

1. Sampleソースの ”console.log” は全て "WScript.Echo" に置換する。
2. ”window.xxxx = function () { “ と対の  “}” は削除する。

「クロージャ(カプセル化)理解すべし!」 という発破を掛けてくれます。さらっと流さないで真面目に取り組みましょう。


ついでのMDNからの解説。正直、上記の【JavaScript入門】と内容は一緒です。


 とにかく、クロージャはJavaScriptでは 覚えておくべき重要な機能なんだぞ、と訴えて来ます。



連想配列やコンストラクタでのコーディング例と比較する

 解かった気がするだけでは微妙な書き方の違いでつまずくので、なんとなく似ている連想配列とコンストラクタとクロージャそれぞれでコーディング例を挙げて比較したいと思います。

 例として "hello" と"たろうさん" という二つの文字列を連結して出力する処理をそれぞれで作成します。

 統一するため、全て『MYAPP.event』に定義してありますので、違いを確認してください。(サンプルコードは 拡張子 js のテキストファイルにコピペしてエクスプローラでダブルクリックすることで実行できます。)

 1. 名前空間に連想配列

 MYAPP.event にオブジェクト定義を行っています。プロパティには.演算子でアクセスしています。WScript.Echo(); の中身の前半は 文字列編集、後半は各オブジェクトの型確認をしています。コードではわかりずらいので実行例の部分を抜き出しておきます。

MYAPP.event.aisatu  // "Hello"
MYAPP.event.name  //  "たろうさん"

 尚、関数 getVal は文法上は正しいのですが、同じ配列の要素である "aisatu" や "name" を引数に指定している為、値を受け取れず 返り値は値無しとなります。


/* ---------------------------------------------- */
/* 空のコンストラクでグローバルオブジェクトを作る */
/* ---------------------------------------------- */
var MYAPP = MYAPP || function(){};  // グローバルオブジェクトはすべて大文字にする、というルールを採用

/* ------------------- */
/* 名前空間に 連想配列 */
/* ------------------- */
MYAPP.event = {
	aisatu : "Hello",
	name : "たろうさん",
	getVal : function(aisatu,name){
		return aisatu + name
	}
};

WScript.Echo(
	      "【名前空間に連想配列】\n"
	+"\n"+ "MYAPP.event.aisatu + MYAPP.event.name=" + "\""+ MYAPP.event.aisatu , MYAPP.event.name + "\"" //"Hello たろうさん"
	+"\n"+ "MYAPP.event.getVal()="  + MYAPP.event.getVal()  // NaN (引数が受け取れない為)
	+"\n"
	+"\n\t"+"["+typeof(MYAPP.event)+"]"          , "MYAPP.event"        // [object] 
	+"\n\t"+"["+typeof(MYAPP.event.aisatu)+"]"   , "MYAPP.event.aisatu" // [string] 
	+"\n\t"+"["+typeof(MYAPP.event.name)+"]"     , "MYAPP.event.name"   // [string] 
	+"\n\t"+"["+typeof(MYAPP.event.getVal)+"]"   , "MYAPP.event.getVal" // [function] 
);  

 実行すると以下の様になります。

画像4


 2. 名前空間にコンストラクタ

 MYAPP.event にコンストラクタ定義を行っています。インスタンス生成の後、メソッド実行しています。WScript.Echo(); の中身の前半は メソッド実行、後半は各オブジェクトの型確認をしています。コードではわかりずらいので実行例の部分を抜き出しておきます。

var myapp = new MYAPP.event('hello', 'たろうさん');  // インスタンス生成
myapp.getVal();     // メソッド実行 


/* ---------------------------------------------- */
/* 空のコンストラクでグローバルオブジェクトを作る */
/* ---------------------------------------------- */
var MYAPP = MYAPP || function(){};  // グローバルオブジェクトはすべて大文字にする、というルールを採用

/* ------------------------ */
/* 名前空間にコンストラクタ */
/* ------------------------ */
MYAPP.event = function(a,b){
	this.aisatu = a;
	this.name = b;
	this.getVal = function(){
		return this.aisatu + this.name;
	};
};

var myapp = new MYAPP.event('hello', 'たろうさん');

WScript.Echo(
	      "【名前空間にコンストラクタ】\n"
	+"\n"+ "myapp.getVal()=" + "\"" + myapp.getVal() + "\""
	+"\n"
	+"\n\t"+"["+typeof(myapp)+"]"       , "myapp"        /* [object]   */
	+"\n\t"+"["+typeof(myapp.aisatu)+"]", "myapp.aisatu" /* [string]   */
	+"\n\t"+"["+typeof(myapp.name)+"]"  , "myapp.name"   /* [string]   */
	+"\n\t"+"["+typeof(myapp.getVal)+"]", "myapp.getVal" /* [function] */ 
);  

 実行すると以下の様になります。

画像4


 3. 名前空間にクロージャ

 MYAPP.event に関数定義を行っています。変数へ関数設定した後、実行しています。WScript.Echo(); の中身の前半は 関数実行、後半は各オブジェクトの型確認をしています。コードではわかりずらいので実行例の部分を抜き出しておきます。

var myAPP = MYAPP.event('hello', 'たろうさん' ); 
myAPP();     // 関数 getVal が実行されている。

 尚、関数(クロージャ)の内側でスコープが有効なので、外部から変数や関数にアクセスすると『undefined』の為、エラーになります。

/* ---------------------------------------------- */
/* 空のコンストラクでグローバルオブジェクトを作る */
/* ---------------------------------------------- */
var MYAPP = MYAPP || function(){};  // グローバルオブジェクトはすべて大文字にする、というルールを採用

/* -------------------- */
/* 名前空間にクロージャ */
/* -------------------- */
MYAPP.event = function(a,b){
	var aisatu = a;
	var name = b;
	getVal = function(){
		return aisatu + name
	};
	return getVal;
};
var myAPP = MYAPP.event('hello', 'たろうさん' );

WScript.Echo(
	      "【名前空間にクロージャ】\n"
	+"\n"+ "myAPP()="+ "\"" + myAPP() + "\""
	+"\n"

	+"\n\t"+"["+typeof(MYAPP.event)+"]"       , "MYAPP.event"        /* [function]  */
	+"\n\t"+"["+typeof(MYAPP.event.aisatu)+"]", "MYAPP.event.aisatu" /* [undefined] */ +" (保護されている)"
	+"\n\t"+"["+typeof(MYAPP.event.name)+"]"  , "MYAPP.event.name"   /* [undefined] */ +" (保護されている)"
	+"\n\t"+"["+typeof(MYAPP.event.getVal)+"]", "MYAPP.event.getVa"  /* [undefined] */ +" (保護されている)"
);  

 実行すると以下の様になります。

画像4







この記事が気に入ったらサポートをしてみませんか?