JavaScript の関数、即時関数 (function(){...})();

更新:

JavaScript の関数、グローバル変数とローカル変数。即時関数 (function(){...})();とは。

関数 function

ナウでヤングな(というほどでもないけど)(function(){...})(); のような関数を書きたい。
(function(){
	//コード
})();
こういう関数を書く前に関数や変数のスコープ、つまりグローバルなのかローカルなのかという話が重要になる。
自分だけがちょっとしたスクリプトを書くなら、関数名、変数名は注意すればかぶる(衝突する)ことはない。
ただ、遠い昔と違い、他人が作ったスクリプトを複数同時に利用することも多くなった昨今、この辺りをしっかりしておかないといけない。


グローバルかローカルか

JavaScriptの変数はvar(letやconstもある)で宣言するが、宣言しなくても動作する。
ただ、varのありなしでスコープが異なり、varがあるとローカル変数、varがないとグローバル変数になる。
var a = 1;//グローバル変数

function ftest(){
	var a = 2;//ローカル変数
	b = 3;//グローバル変数
}

ftest();
console.log(a);//1
console.log(b);//3
上の例では b はグローバル変数になる(恐ろしい)。
PHPではこうならないが、これはJavaScriptの昔からの仕様で、うっかり var を付け忘れると大変なことになる可能性がある。
関数内と外に同名の変数 a あるが、関数内の a は var を書いたので、この関数内で使えるローカル変数になり、グローバル変数の a とは別物。
もし var を書かず単に a = 2; とした場合はグローバル変数の a に 2 を代入することになるので、console.log(a) の結果は 2 になる。
var a = 1;

function ftest(){
	var a = 2;
	console.log(a);//2
	console.log(window.a);//1
}

ftest();
上の例では、window.a はグローバル変数の方の a になり、関数内で使うことができる。
では、関数の引数はどうなるのか。
var a = [1, 2];
var b = 10;

function ftest(a, b){
	b++;
	a.push(b);
	return a;
}
console.log(ftest(a, b));//Array [ 1, 2, 11 ]
console.log(a);//Array [ 1, 2, 11 ](Array [ 1, 2 ]ではない)
console.log(b);//10(11ではない)
function ftest(a, b) と書けば、基本的に変数 a, b を宣言したのと同じ。
ただし、配列など参照型の場合、上の例のように関数内の処理がグローバルに影響する。


let のブロックスコープ

例えば、他の言語のようにfor文を書くと大変なことになる。
function ftest(){
	for(i=1;i<=5;i++){
		//iはグローバル変数(関数外でも有効)
	}
	
	for(var j=1;j<=5;j++){
		//jはローカル変数(関数内で有効)
	}
	
	for(let k=1;k<=5;k++){
		//kはこのforブロック内でのみ有効
	}
}
for文で変数を使う際、varで宣言した i や j などを使うが、letという便利なものがあり、これは for や if などブロック内でのみ有効な変数を宣言できる。
特にforブロックで有用と思われる。


関数式

JavaScriptでは関数と式が合わさった形も見かけ、妙な感じだが、こういう書き方ができる。
var ftest = function(a, b){
	return a * b;
};
console.log(ftest(2, 3));//6
式なので末尾に ;(セミコロン)がある。
また、関数名を書くこともできるが、この例では関数名を省略している。
こういう関数は無名関数と呼ばれている。
関数名がかぶる心配がなく、関数内の変数は var 等でローカル変数にできる。


即時関数 (function(){...})();

冒頭で (function(){...})(); というのを書いたが、この関数は一部で即時関数と呼ばれているので、ここでもそう呼ぶことにする。
即時関数は、前述の関数式を関数だけにし、括弧を付けたのような形をしている。
頭がfunctionで始まると関数文として認識されるが、括弧などを付けると式として認識される。
最後の () がないと実行されないが、エラーは出ない。
いくつか書き方がある。
//最後の () が外
(function(){
	//コード
})();
//最後の () が中
(function(){
	//コード
}());
どちらも結果は同じ。
先ほど「括弧など」と言ったが、functionの前に !(ビックリマーク、エクスクラメーション)を書いても良い。
//先頭に !
!function(){
	//コード
}();
! の他に + や - や ~ でも同じ。

通常、関数内の処理を行うにはどこかで関数を呼ばないといけないが、即時関数は即実行される。
var a = 1;//グローバル変数

(function(){
	var a = 2;//ローカル変数
	b = 3;//グローバル変数
})();

console.log(a);//1
console.log(b);//3
当然、関数だから即時関数内の変数は var 等でローカル変数にできる。
また、無名関数だから関数名がかぶる心配もない。
用途としてはGoogleアナリティクスのようなものがある。
(function(a, b){
	console.log(a * b);//30
})(5, 6);
上の例はGoogleアナリティクス風に引数を使って書いた。
総論としては、同一ページにいろいろな人が作ったスクリプトが入り乱れる昨今、関数や変数のスコープを限定する工夫が必要という話。
遠い昔、今ほどJavaScriptが使われるようになるとは思わなかった。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions_and_function_scope

innerHTML、insertAdjacentHTMLの違い へ続く。
このエントリーをはてなブックマークに追加