自己定義関数
var devour = function(target){
//1回目の実行のみ実行される
console.log('ゲルトが無残な姿で発見されました。');
//devourを再定義
devour = function(target){
//2回目以降実行される
console.log(target + 'が無残な姿で発見されました。');
}
}
devour('ヨアヒム'); //ゲルト
devour('リーザ'); //リーザ
devour('ペーター'); //ペーター
関数のなかで実行した関数を再定義すると、初回のみ実行したい処理をひとつの関数のなかで分離できる。
また、再定義後のスコープ内に再定義前のスコープ変数への参照を持っていれば、その参照を保持しているのでクロージャとしても使える。
var visitCount = function(){
var count = 1;
console.log('はじめまして! ○○さん');
visitCount = function(){
count++;
console.log(count + '回目の訪問です');
}
}
visitCount(); //はじめまして! ○○さん
visitCount(); //2回目の訪問です。
visitCount(); //3回目の訪問です。
連鎖代入
JavaScriptの代入は式なので、演算結果を同じ文のなかでそのままさらに代入することができる(連鎖代入)。
複数の変数にまとめて代入することが必要な場合、以下のように書くことが出来る。
var pamela = otto = 'werewolf';
console.log(pamela); // werewolf
console.log(otto); // werewolf
一見便利だがスコープの観点からみればあまり好ましくない結果を生んでいる。
たとえば下記のような代入の連鎖は、グローバル空間を汚染している。
// 即時関数で括ってスコープを限定!
(function () {
var pamela = otto = 'werewolf';
})();
console.log(pamela); // undefined → ok
console.log(otto); // werewolf → 見えちゃってる
これは、代入演算子の評価が右結合であることによる。
文『var pamela = otto = 'werewolf';』では、まず式『otto = 'werewolf'』が評価されてしまうため、ottoはグローバル変数として登録されてしまう。 続いて式『var pamela = otto』が評価されるため、var pamelaはグローバルスコープから見えずundefinedとなる。
連鎖代入を用いつつ、pamera・ottoともにスコープをローカルに限定するにはカンマ演算子を使う。
// 即時関数で括ってスコープを限定!
(function () {
var pamela, otto;
pamela = otto = 'werewolf';
})();
console.log(pamela); // undefined
console.log(otto); // undefined