functionの正体を知らない【1】

9896 ワード

**この記事はhttp://bbs.csdn.net/topics/300068173 自分の勉強経験を共有してくれた皆さんに感謝しています.道を模索している人たちが先輩の心得を学び続けています.**
JAvascriptの関数は他の言語とは異なり、各関数はオブジェクトとして維持され、実行されます.関数オブジェクトの性質により、1つの関数を変数に割り当てるか、関数をパラメータとして渡すことが容易になります.まず、関数の使用文法を見てみましょう.関数を宣言するには、次の方法があります.
   var func2=function(…){…}; 
   var func3=function func4(…){…}; 
   var func5=new Function();  
関数とは?【Know the function object】
functionキーワードで関数を定義し、各関数に関数名を指定して関数名で呼び出すことができます.
function add(){
   console.log("hello");
}  //    
add(); //      ()       
JavaScript解釈が実行されると、関数はすべて1つのオブジェクトとして維持されます.これが、説明する関数オブジェクト(Function Object)です.
関数オブジェクトは,ユーザが定義したオブジェクトと本質的に異なる.ユーザ定義オブジェクトは、日付ペア(Date)、配列オブジェクト(Array)、文字列オブジェクト(String)などの内部オブジェクトと呼ばれます.これらの組み込みオブジェクトのコンストラクタはJavaScript自体によって定義されています.new Array()という文を実行することでオブジェクトを返します.JavaScriptの内部には、ユーザーがオブジェクトの構造を指定するのではなく、返されたオブジェクトを初期化するメカニズムがあります.
JavaScriptでは、関数オブジェクトに対応するタイプがFunctionで、配列オブジェクトに対応するタイプがArray、日付オブジェクトに対応するタイプがDateのようになっています.new Function()を使用して関数オブジェクトを作成するか、functionキーワードを使用してオブジェクトを作成できます.まず、配列オブジェクトを見てください.次の2行のコードは、配列オブジェクトmyArrayを作成します.
var myArray=[]; 
//    
var myArray=new Array(); 
次の2つのコードも関数myFunctionを作成します.

function myFunction(a,b){ 
      return a+b; 
} 
//    
var myFunction=new Function("a","b","return a+b");   
構造配列オブジェクト文との比較により,関数オブジェクトの本質が明確に見える.前述した関数宣言は、上記のコードの最初の方法であり、解釈器の内部では、この構文に遭遇すると、自動的にFunctionオブジェクトが構築され、関数が内部のオブジェクトとして格納され、実行されます.ここからも、1つの関数オブジェクト名(関数変数)と通常の変数名は同じ仕様を有し、変数名でこの変数を参照できますが、関数変数名の後ろにカッコとパラメータリストを付けて関数呼び出しを行うことができます.new Function()の形式で1つの関数を作成するのは一般的ではありません.1つの関数体には通常複数の文があり、1つの文字列の形式でパラメータとして渡されると、コードの可読性が悪くなります.使用法について説明します.
var funcName=new Function(p1,p2,...,pn,body); 
パラメータの種類はすべて文字列で、p 1からpnは作成した関数のパラメータ名のリストを表し、bodyは作成した関数の関数体文を表し、funcNameは作成した関数の名前である.パラメータを指定せずに空の関数を作成したり、funcNameを指定せずに無名の関数を作成したりすることができます.もちろん、そのような関数には意味がありません.
なお、p 1~pnはパラメータ名のリストである.すなわち、p 1はパラメータを表すだけでなく、カンマで区切られたパラメータリストであってもよい.例えば、以下の定義は等価である.
new Function("a", "b", "c", "return a+b+c") 
new Function("a, b, c", "return a+b+c") 
new Function("a,b", "c", "return a+b+c") 
JavaScriptがFunctionタイプを導入し、new Function()という構文を提供するのは、関数オブジェクトに属性とメソッドを追加するにはFunctionというタイプを利用しなければならないからです.
関数の本質は、JavaScriptインタプリタによって実行方法が決定される内部オブジェクトです.上記のコードで作成した関数は、プログラムで関数名を使用して呼び出すことができます.このセクションの冒頭にリストされた関数定義の問題も説明されています.注記:
var i=function (a,b){ 
       return a+b; 
 }(1,2); 
alert(i);  // 3
このようなコードは一般的ではないかもしれませんが、ユーザーが長いコードセグメントでモジュール化設計を行いたい場合や、名前の競合を回避したい場合は、良い解決策です.
次の2つの関数を作成する方法は等価ですが、
function funcName(){ 
       //    
} 
//    
var funcName=function(){ 
       //    
}  
しかし、前の方法では有名な関数が作成され、後ろには無名の関数が作成され、変数がこの無名の関数を指すだけです.使用上の違いは、有名な関数の場合、呼び出し後に定義できることです.無名関数の場合は、呼び出す前に定義されている必要があります.例:
<script language="JavaScript" type="text/javascript"> 
func(); 
var func=function(){ 
       alert(1) 
} 
</script>
この文はfuncが定義していないエラーを生成します.
<script language="JavaScript" type="text/javascript"> 
func(); 
function func(){ 
      alert(1) 
} 
</script>  
次の文も正しく実行されます.
<script language="JavaScript" type="text/javascript"> 
func(); 
var someFunc=function func(){ 
      alert(1) 
} 
</script>  
このように、JavaScriptは解釈型の言語ですが、関数呼び出し時にコード全体に対応する関数定義があるかどうかを確認します.この関数名はfunction funcName()形式で定義されている場合にのみ有効であり、匿名関数数ではありません.
関数オブジェクトとその他の内部オブジェクトの関係【relation of other objects】
関数オブジェクトのほかにも、Object、Array、Date、RegExp、Math、Errorなどの内部オブジェクトがたくさんあります.これらの名前は実際にはタイプを表し、newオペレータでオブジェクトを返すことができます.しかし、関数オブジェクトは他のオブジェクトとは異なり、typeofで関数オブジェクトのタイプを取得すると、文字列「function」が返され、typeofの配列オブジェクトまたは他のオブジェクトが返されると、文字列「object」が返されます.次のコードはtypeofの異なるタイプの場合を示します.
       console.log(typeof(Function ));  //function
       console.log(typeof(Array ));   //function 
       console.log(typeof(Object )); //function
       //    function             
       【           。。】

       console.log(typeof(new Function )); //function

       console.log(typeof(new Array ));  //object 
       console.log(typeof(new Date ));   //object 
       console.log(typeof(new Object ));  //object 
このコードを実行すると、newの1つのFunctionは実際には関数を返し、他のものはオブジェクトを返すことがわかります.これは他のオブジェクトとは大きく異なります.他のタイプのArray、Objectなどはnewオペレータで通常のオブジェクトを返します.関数自体もオブジェクトですが、通常のオブジェクトとは異なります.これは、オブジェクトコンストラクタでもあります.つまり、newの関数を使用してオブジェクトを返すことができます.これは前述しています.すべてのtypeofが「function」を返すオブジェクトは関数オブジェクトです.このようなオブジェクトもコンストラクタ(constructor)と呼ばれ、したがって、すべてのコンストラクタはオブジェクトであるが、すべてのオブジェクトがコンストラクタであるわけではない.
関数自体もオブジェクトである以上、それらのタイプはfunctionであり、C++、Javaなどのオブジェクト向け言語のクラス定義を連想し、Functionタイプの役割を推測することができる.それは、関数オブジェクト自体にいくつかの方法と属性を定義することができ、関数のprototypeオブジェクトを利用して、Functionタイプの定義を容易に修正し、拡張することができる.たとえば、次の関数タイプFunctionを拡張してmethod 1メソッドを追加し、ポップアップダイアログボックスに「function」を表示します.
Function.prototype.method1=function(){ 
      alert("hello"); 
} 
function func1(a,b,c){ 
      return a+b+c; 
} 
func1.method1(); 
func1.method1.method1();  
最後の文:func 1.method 1.mehotd 1()は、method 1という関数オブジェクトのmethod 1メソッドを呼び出します.少し混同しやすいように見えますが、文法をよく見てみると、これは再帰的な定義です.method 1自体も関数であるため,関数オブジェクトの属性とメソッドを同様に持ち,Functionタイプのメソッド拡張に対してすべてこのような再帰的性質を持つ.