JavaScript関数式


関数式の特徴:
定義関数には2つの方法があります.一つは関数宣言で、一つは関数式です.
関数宣言、
関数宣言はアップグレードされます.
コードを実行する前に関数宣言を読みます.
関数の呼び出し文は、関数宣言文の前に表示されます.
function name(){}
関数式は、変数の割り当てに似ています.この関数を匿名関数と呼びます.
var name = function(){}
再帰する
関数は名前で自身を呼び出します.
function factorial (num){
     if(num <= 1){
          return 1;
     }else{
          return num*factorial(num-1);
     }
}
ですが、関数名で呼ばれると危険です.
var anotherFunction = factorial;
factorial = null;
alert(anotherFunction (5)); //  
元の関数名はもう関数ではありません.この解決方法は関数オブジェクトの属性アーグメンント.
argments.calleeは、実行中の関数を指すポインタですので、再帰的な呼び出しが可能です.
function factorial (num){
     if(num <= 1){
          return 1;
     }else{
          return num * arguments.callee(num-1);
     }
}
ですが、ここにあります
厳密モードでは、スクリプトがargments.calee属性にアクセスできませんでしたが、
名前付き関数式によって同じ結果が得られます.
var factorial = (function f(num){
     if(num <= 1)return 1;
     else return mun * f(num-1);
});
は、厳密で非厳密なモードでも良いように、f()の命名関数式を作成しました.
ECMAScriptの関数名自体が変数ですので、関数は値として使用できます.伝達パラメータのように関数を別の関数に伝達するだけでなく、関数を別の関数の戻り値としてもいいです.
クローズド(Cloure)
クローズドは何ですか
JavaScript高級プログラム設計(第3版)の定義:クローズドは 
別の関数のスコープ内の変数にアクセスできる関数を指します. クローズドパッケージの作成には、通常の方法があります.
関数で別の関数を作成します.クローズドとは、関数内部と外部をリンクする橋のことと考えられます.
その他の定義または理解方法:
特徴的には、 
クローズドとは、関数の局所変数の集合です.ただし、これらの局所変数は関数が戻った後も存在します.
言語の特性から: 
クローズドとは関数の「スタック」であり、関数が戻った後は解放されません.これらの関数スタックはスタックに割り当てられず、スタックに割り当てられているということも理解できます.
作用ドメインチェーンの詳細から閉ループを理解する:
作用するドメインチェーンの出現は、実行環境にアクセスできる関数と変数の秩序的なアクセスを保証するためである.スコープの先端は常にコードが実行されている環境の変数です.この環境が関数である場合は、
アクティブオブジェクト(関数の活動オブジェクトはthis、argments、および着信パラメータを含む)が変数オブジェクトとして作用するフィールドチェーンの次の変数オブジェクトは外部(含む)環境から来て、次の変数は次の環境から来て、グローバル環境に至るまで続きます.グローバル実行環境の変数は、作用するフィールドチェーンの最後のオブジェクトです.
識別子の解析プロセスは、識別子が見つかるまで、ドメインチェーンの前端を段階的に後へ遡る.
フィールドチェーンは、実際の変数オブジェクトだけを参照して参照しているが、実際の変数オブジェクトは含まれていません.
一般的には関数の実行が終了すると、局部の活動対象は廃棄されます.メモリにはグローバル実行環境の変数オブジェクトだけが残っていますが、クローズドの場合はありません.
関数の内部で定義された関数は、外部関数の活動オブジェクトを自身の作用ドメインチェーンに追加します.匿名の関数は外部関数で返された後、その作用領域チェーンは外部関数の活動オブジェクトとグローバル変数オブジェクトを含み、内部の匿名関数は外部関数で定義されたすべての変数にアクセスできます.より重要なのは、外部関数が実行された後、その活動オブジェクトは破壊されずにメモリに保存されます.これらの変数が戻ってくる匿名関数が参照されているからです.匿名関数に戻る参照が解除された場合(戻り値を保存する変数をnullに設定すると参照を解除します)、匿名関数は破棄され、外部関数の活動対象は破棄されます.
下の説明は上の説明と同じ意味です.
coolshell.cn  JavaScriptのクローズド:どのような状況で関数内部の変数がごみ回収機構によって回収されていないかを説明しました.(
jsのゴミ回収アルゴリズムは、一つは「マーククリア」、もう一つは「参照カウント」です.
一つのfunctionオブジェクト内にFunction本体だけでなく、現在のスコープの参照もあります.
このようなfunctionとそのfunction変数の作用域を決定する組み合わせはコンピュータ科学において閉包と呼ばれています.
一つのfunctionが呼び出されるたびに、新しいオブジェクトが自動的に作成され、関連するlocal変数を保存するために使用されます.このバインディングオブジェクトは作用するドメインチェーンに追加されます.関数が戻ると、その保存されたオブジェクトは作用するドメインチェーンから削除されます.
機能がネストされていない場合は、対応するバインディングオブジェクトに余分な参照がなく、関数が戻った後に正常なゴミ回収機構が起動されます.functionがネストされて他のfunction内部に定義されている場合は、
各functionには、作用するドメインチェーンのバインディングオブジェクトの参照があります.内部functionが外部のfunctionに残しておくと、それ自体やバインディングオブジェクトもゴミで回収されます.しかし、外部functionが内部定義のfunctionをどこかに保存すると、内部functionの外部参照が生まれます.この場合、内部functionとそのバインディングオブジェクトは全部です.回収されません
一つの注意すべき問題
作用する分域鎖という機構がクローズドに導入された副作用は,クローズドは外部関数の活動対象の最後の値しか得られない.
    :
function f(){
     var result = new Array();
     for(var i = 0; i< 10; i++){
          result[i] = function(){
          return i;
          };
     }
     return result;
}
    var a = f();
    for(var i = 0; i<10;i++){
        console.log("a["+i+"]() = "+ a[i]());
    }

//       10;
戻ってきた各作用領域チェーンはf()関数の活動対象として保存されていますので、それらは最初の変数i、f()関数を参照して返した後、iの値は10です.この時、各関数は変数iが保存されている同じ変数オブジェクトを参照します.したがって、各関数の内部iの値は10です.
匿名関数を使って強制的にクローズド行為を予想通りにすることができます.
function f(){
     var result = new Array();
     for(var i = 0; i< 10; i++){
          result[i] = function(num){
          //        num       
          return function(){
              return num; 
          };
          }(i);
     }
     return result;
}
    var a = f();
    for(var i = 0; i<10;i++){
        console.log("a["+i+"]() = "+ a[i]());
    }
は、したがって、それぞれの異なる値を返すことができる.
thisオブジェクト関連:
thisは実行時関数に基づいて環境バインディングを実行し、大域でthisはwindowに等しく、関数があるオブジェクトの方法として呼び出された場合、thisはそのオブジェクトに等しくなります.
var name = "window";
var a = {
     name : "a",
     getName : function(){
          return function(){
              return this.name; 
          };
     }
};
alert(a.getName()()); //window
なぜかというと、内部関数は自分の活動対象のthisにしかアクセスできないので、argmentsは外部関数のこの二つの変数に直接アクセスすることは永遠に不可能です.
ただし、外部関数のthisオブジェクトをクローズドでアクセスできる変数に保存することができます.
var name = "window";
var a = {
     name : "a",
     getName : function(){
          var that = this;
          return function(){
              return that.name; 
          };
     }
};
alert(a.getName()()); //a
ブロックレベルのスコープを模倣する
jsはブロックレベルのスコープの概念がなく、ブロックレベルのステートメントで定義される変数は、実際にはステートメントではなく関数を含む中で作成されます.
ブロックレベルのスコープは匿名関数でモデル化できます.文法は以下の通りです.
JavaScriptでグローバル変数を処理するには、この方法が使われています.
方式は以下の通りです
(function(){
     //         
})();
は、このようにして理解することができ、
var f = function(){
};
f();
匿名関数を変数に割り当て、それを呼び出し、変数fを実際の関数値で置き換えることができます.
function(){
}();
しかし、このように文法的なエラーを引き起こす可能性があります.JavaScriptは関数宣言の始まりとして機能宣言を行います.関数宣言の後には括弧を付けられません.しかし、関数式の後には括弧を付けられます.関数宣言を関数式に変換して括弧を付ければいいです.
(function(){
     //         
})();
どこでも、いくつかの臨時変数が必要であれば、このようなプライベートブロックレベルの作用領域を利用して、匿名関数に定義された変数を変更すると、関数の実行が終了した時点で廃棄されます.
この技術はしばしば大域作用域の関数において関数の外部に使用され、大域作用域に多すぎる変数と関数を追加することを制限します.このように開発者は自分の変数を使用できます.大域作用領域を混乱させる心配がありません.