mozilla
Your Search Results

    関数

    関数は、JavaScript の基本的な構成要素のひとつです。また関数は、JavaScript のプロシージャです。つまり、タスクや値の計算を実行する文の集まりです。関数を使うには、それを呼び出したいスコープ内のどこかで定義しなければなりません。

    関数の定義

    関数の定義 (関数の宣言 とも呼ばれます) は function キーワードと、それに続く以下の内容で構成されます。

    • 関数の名前。
    • 関数への引数のリスト。丸括弧でくくり、コンマで区切ります。
    • 関数を定義する JavaScript の文。波括弧 { } でくくります。

    例えば、次のコードは square という名前の簡単な関数を定義します:

    function square(number) {
      return number * number;
    }

    関数 square は引数を 1 つとり、その名前は number です。この関数は、引数 (すなわち number) の 2 乗を返すように指示する 1 つの文で構成されます。return 文は、関数が返す値を指定します。

    return number * number;
    

    プリミティブなパラメータ (数値など) は値渡しで関数に渡されます。つまり、値は関数に渡されますが、関数がパラメータの値を変更しても、この変更はグローバル (のパラメータの値) や関数の呼び出し元 (のパラメータの値) には影響を与えません。

    オブジェクト (すなわち非プリミティブ値、例えば配列やユーザ定義オブジェクトなど) をパラメータとして渡すと、関数がオブジェクトのプロパティを変更した場合に、その変更が関数外でも有効になります。次の例をご覧ください:

    function myFunc(theObject) {
      theObject.make = "Toyota";
    }
    
    var mycar = {make: "Honda", model: "Accord", year: 1998},
        x,
        y;
    
    x = mycar.make;     // x は "Honda" という値を得る
    
    myFunc(mycar);
    y = mycar.make;     // y は "Toyota" という値を得る
                        // (プロパティが関数で変更されている)
    

    パラメータに新たなオブジェクトを代入しても、関数の外部には影響が及ばないことに注意してください。これは、オブジェクトのいずれかのプロパティの値ではなく、パラメータの値を変更しているためです:

    function myFunc(theObject) {
      theObject = {make: "Ford", model: "Focus", year: 2006};
    }
    
    var mycar = {make: "Honda", model: "Accord", year: 1998},
        x,
        y;
    
    x = mycar.make;     // x は "Honda" という値を得る
    
    myFunc(mycar);
    y = mycar.make;     // y はやはり "Honda" という値を得る 
    

    1 番目の例では、オブジェクト mycar が関数 myFunc に渡され、改変されます。2 番目の例では、関数は渡されたオブジェクトを改変しません。代わりに、渡されたグローバルオブジェクトとたまたま同じ名前を持つ、新たなローカル変数を作成しますので、渡されたグローバルオブジェクトには影響がありません。

    JavaScript では、条件に基づいて関数を定義することもできます。例えば次の関数の定義は、変数 num が 0 に等しい場合のみ myFunc という関数を定義します:

    if (num == 0){
      function myFunc(theObject) {
        theObject.make = "Toyota"
      }
    }
    

    num が 0 に等しくない場合は関数が定義されず、その関数を実行しようとしても失敗します。

    ECMAScript は、このようにコンテキスト内で関数が現れることを認めておらず、別の関数内またはプログラムのトップレベルのみとしています。よって、この例は ECMAScript として不正です。

    警告: この非標準構造は、別の JavaScript の実装では異なる扱いを受けますので、可搬性があるコードを記述する際は避けるべきです。さもなければコードが、あるブラウザでは動作するが別のブラウザでは動作しない状態になるかもしれません。

    これまで説明してきた関数の定義に加えて、Function コンストラクタを、eval() のように文字列からの関数作成に用いることができます。

    メソッド は、オブジェクトのプロパティである関数のことです。オブジェクトとメソッドについて詳しくは、Working with Objects をご覧ください。

    これまでの関数宣言はすべて構文的な文でしたが、関数は関数式によって作成することもできます。このような関数は無名にできます。名前をつけなくてもよいのです。例えば、関数 square は次のように定義できます:

    var square = function(number) {return number * number};
    

    ただし関数式は名前をつけることもでき、関数内で自身を参照することや、デバッガのスタックトレースで関数を特定することに利用できます:

    var factorial = function fac(n) {return n<2 ? 1 : n*fac(n-1)};
    
    print(factorial(3));
    

    関数式は、ある関数を別の関数の引数として渡すときに便利です。次の例では map 関数を定義し、第 1 パラメータとして無名関数を指定して呼び出します:

    function map(f,a) {
      var result = [], // 新しい配列を作成
          i;
      for (i = 0; i != a.length; i++)
        result[i] = f(a[i]);
      return result;
    }
    

    例えば、以下のように呼び出します:

    map(function(x) {return x * x * x}, [0, 1, 2, 5, 10]);
    

    これは [0, 1, 8, 125, 1000] を返します。

    関数の呼び出し

    関数を定義しても、その関数は自動的に実行されるわけではありません。関数を定義するということは単に関数に名前をつけ、その関数が呼び出されたときに何をするかを指定することです。関数の呼び出しとは、実際には指定されたパラメータを用いて指定された動作を実行するということです。例えば、関数 square を定義した場合、次のようにしてそれを呼び出すことができます:

    square(5);
    

    この文は 5 という引数とともに関数を呼び出します。関数は自身の文を実行し、25 という値を返します。

    関数は呼び出されるスコープ内になければいけませんが、次の例のように、関数の宣言は呼び出しより後に置くことができます:

    print(square(5));
    /* ... */
    function square(n){return n*n}
    

    関数のスコープは自身が宣言された関数内、あるいはトップレベルで宣言されたのであればプログラム全体になります。この動作は、上記の構文 (すなわち function funcName(){}) を用いて関数を定義したときに限ることに注意してください。次のコードは動作しません。

    print(square(5));
    square = function (n) {
      return n * n;
    }
    

    関数の引数は、文字列や数値に限られてはいません。オブジェクト全体を関数に渡すこともできます。show_props 関数 (オブジェクトとプロパティで定義) は、オブジェクトを引数にとる関数の例です。

    関数は再帰的にすることもできます。つまり、ある関数がその関数自身を呼び出すこともできるということです。例えば、ここに階乗を計算する関数を示します:

    function factorial(n){
      if ((n == 0) || (n == 1))
        return 1;
      else
        return (n * factorial(n - 1));
    }
    

    1 から 5 までの階乗の計算は、次のようになります:

    var a, b, c, d, e;
    a = factorial(1); // a は値 1 を得る
    b = factorial(2); // b は値 2 を得る
    c = factorial(3); // c は値 6 を得る
    d = factorial(4); // d は値 24 を得る
    e = factorial(5); // e は値 120 を得る
    

    関数を呼び出す方法は他にもあります。関数が動的に呼び出される必要がある、関数の引数の数を変える、関数を呼び出すコンテキストを実行時に決まる特定のオブジェクトにセットする必要があるといった場合があります。関数は関数であるとともにオブジェクトでもあり、また結果としてそれらのオブジェクトはメソッドを持っています (Function オブジェクト をご覧ください)。それらメソッドのひとつ、apply() メソッドを用いることでこの目的を実現できます。

    関数のスコープ

    関数の内部で宣言された変数は、関数の外部からアクセスすることができません。これは、変数が関数のスコープ内でのみ定義されているためです。しかし、関数は自身が定義されたスコープ内で定義されているすべての変数や関数にアクセスできます。言い換えると、グローバルスコープで定義された関数は、グローバルスコープで定義されたすべての変数にアクセスできます。ある関数の内部で宣言された関数は、自身の親の関数内で定義されたすべての変数や、親の関数がアクセス権を持つ他の変数にもアクセスできます。

    // 以下の変数はグローバルスコープで定義
    var num1 = 20,
        num2 = 3,
        name = "Chamahk";
    
    // この関数はグローバルスコープで定義
    function multiply() {
      return num1 * num2;
    }
    
    multiply(); // 60 を返す
    
    // 入れ子になっている関数の例
    function getScore () {
      var num1 = 2,
          num2 = 3;
      
      function add() {
        return name + " scored " + (num1 + num2);
      }
      
      return add();
    }
    
    getScore(); // "Chamahk scored 5" を返す
    

    クロージャ

    クロージャは、JavaScript でもっとも強力な機能のひとつです。JavaScript では関数の入れ子が可能であることに加えて、内側の関数が外側の関数内で定義されたすべての変数や関数に、自由にアクセスできます (さらに、外側の関数がアクセスできる、他の変数や関数すべてにもアクセスできます)。しかし、外側の関数は内側の関数内で定義された変数や関数にアクセスできません。これは、内側の関数の変数に対する一種のセキュリティです。また、内側の関数は外側の関数のスコープにアクセスできることから、外側の関数内で定義された変数や関数は、外側の関数の生存期間を越えて残すように内側の関数が管理する場合に、外側の関数自体より長く残る可能性があります。クロージャは、内側の関数がどうにかして外側の関数の外部のスコープを使用可能にするときに作成されます。

    var pet = function(name) {          // 外側の関数は変数 "name" を定義
          var getName = function() {
            return name;                // 内側の関数は外側の関数の変数 "name" にアクセス可能
          }
    
          return getName;               // 内側の関数を返すことで、外側の関数に公開する
        },
        myPet = pet("Vivie");
        
    myPet();                            // "Vivie" を返す
    

    上記のコードより複雑なコードにすることもできます。外側の関数の内部にある変数を操作するメソッドを含む、オブジェクトを返すことができます。

    var createPet = function(name) {
      var sex;
      
      return {
        setName: function(newName) {
          name = newName;
        },
        
        getName: function() {
          return name;
        },
        
        getSex: function() {
          return sex;
        },
        
        setSex: function(newSex) {
          if(typeof newSex == "string" && (newSex.toLowerCase() == "male" || newSex.toLowerCase() == "female")) {
            sex = newSex;
          }
        }
      }
    }
    
    var pet = createPet("Vivie");
    pet.getName();                  // Vivie
    
    pet.setName("Oliver");
    pet.setSex("male");
    pet.getSex();                   // male
    pet.getName();                  // Oliver
    

    上記の例で、外側の関数の変数 name は内側の関数からアクセスでき、また内側の関数を通さずに内側の変数へアクセスする他の方法はありません。内側の関数の内部変数は、内側の関数の安全な保存領域として振る舞います。それらは内側の関数向けに協働するデータを、"永続的" かつ安全に保持します。関数は変数を割り当てられる必要さえなく、また名前を持つ必要もありません。

    var getCode = (function(){
      var secureCode = "0]Eal(eh&2";    // 外部の関数が変更できないようにしたいコード
      
      return function () {
        return secureCode;
      };
    })();
    
    getCode();    // シークレットコードを返す
    

    ただし、クロージャを使用する際に注意すべき落とし穴がいくつかあります。取り囲まれている関数で外側のスコープにある変数と同じ名前の変数を定義した場合、外側のスコープにある変数を再び参照する方法がなくなります。

    var createPet = function(name) {  // 外側の関数で変数 "name" を定義
      return {
        setName: function(name) {    // 内側の関数でも変数 "name" を定義
          name = name;               // ???外側の関数で定義した "name" へどのようにしてアクセスするのか ???
        }
      }
    }
    

    魔法のような変数 this は、クロージャ内でとても扱いにくいものです。this の参照先は、関数が定義された場所ではなく関数が呼び出された場所に対して全面的に依存するため、注意して使用しなければなりません。クロージャに関するすばらしく、かつ精巧な記事がこちらにあります。

    arguments オブジェクトの使用

    関数の引数は、配列のようなオブジェクトで管理されます。関数内では、次のようにして渡された引数を指すことができます:

    arguments[i]
    

    ここで i は引数の順序を表す数を指します。これは 0 から始まります。関数に渡された第 1 引数は arguments[0] となります。引数のトータルの数は arguments.length で表されます。

    arguments オブジェクトを使用すると、宣言時の仮引数の数よりも多くの引数を用いて関数を呼び出すことができます。これは、関数に渡す引数の数が前もってわからない場合に役立ちます。arguments.length を使用することで、実際に関数に渡された引数の数を特定することができます。また、arguments オブジェクトを使用することで、各引数を扱うことができます。

    例えば、複数の文字列を連結する関数を考えます。この関数の仮引数は、連結するアイテムを区切るのに用いる文字列のみです。この関数は次のように定義されています:

    function myConcat(separator) {
       var result = "", // リストを初期化する
           i;
       // 引数について繰り返し
       for (i = 1; i < arguments.length; i++) {
          result += arguments[i] + separator;
       }
       return result;
    }
    

    この関数に引数をいくつも渡すことができます。そして、各引数を文字列の "リスト" に連結します:

    // "red, orange, blue, " を返す
    myConcat(", ", "red", "orange", "blue");
    
    // "elephant; giraffe; lion; cheetah; " を返す
    myConcat("; ", "elephant", "giraffe", "lion", "cheetah");
    
    // "sage. basil. oregano. pepper. parsley. " を返す
    myConcat(". ", "sage", "basil", "oregano", "pepper", "parsley");
    

    変数 arguments は "配列のような変数" であり、配列ではないことに注意してください。これは数値のインデックスと length プロパティがあることで、配列のようなものになります。しかし、配列操作のメソッドはまったく持っていません。

    さらなる情報については、JavaScript リファレンスの Function オブジェクトをご覧ください。

    定義済み関数

    JavaScript には、定義済みのトップレベル関数がいくつかあります:

    以下の章で、これらの関数を説明します。なお全関数の詳細情報については、JavaScript リファレンスをご覧ください。

    eval 関数

    eval 関数は JavaScript のコード文字列を、特定のオブジェクトを参照することなく評価します。eval の構文は次のとおりです:

    eval(expr);
    

    ここで expr は、評価される文字列です。

    文字列が式を表している場合は、eval はその式を評価します。また 1 つ以上の JavaScript の文を表している場合は、eval はその式を実行します。eval のコードのスコープは、呼び出し元コードのスコープと同じです。演算式を評価するために eval を呼び出さないでください。JavaScript は自動的に演算式を評価します。

    isFinite 関数

    isFinite 関数は引数を評価し、それが有限数であるかを判断します。isFinite の構文は次のとおりです:

    isFinite(number);
    

    ここで number は、評価する数値です。

    引数が NaN、正の無限大、または負の無限大である場合、このメソッドは false を返し、そうでない場合は true を返します。

    次のコードはクライアントの入力をチェックし、それが有限数であるかを判断します。

    if(isFinite(ClientInput)){
       /* 適当な処理 */
    }
    

    isNaN 関数

    isNaN 関数は引数を評価し、それが "NaN" (not a number; 非数) であるかを判断します。isNaN の構文は次のとおりです:

    isNaN(testValue);
    

    ここで testValue は、評価したい値です。

    parseFloat および parseInt 関数は、非数を渡したときに "NaN" を返します。isNaN は "NaN" が渡された場合は trne を、そうでない場合は false をそれぞれ返します。

    次のコードは floatValue を評価し、それが数値であるかを判断し、その結果に応じてプロシージャを呼び出します:

    var floatValue = parseFloat(toFloat);
    
    if (isNaN(floatValue)) {
       notFloat();
    } else {
       isFloat();
    }
    

    parseInt 関数および parseFloat 関数

    2 つの「パース」関数、parseInt および parseFloat は、引数に文字列が与えられたときに数値を返します。

    parseFloat の構文は次のとおりです:

    parseFloat(str);
    

    parseFloat は引数である文字列 str をパースし、浮動小数点数を返そうとします。符号 (+ または -)、数字 (0-9)、小数点、または指数以外の文字に出くわすと、そこまでの値を返し、その文字および後続の文字すべてを無視します。最初の文字が数値に変換できない場合は、"NaN" (not a number; 非数) を返します。

    parseInt の構文は次のとおりです:

    parseInt(str [, radix]);
    

    parseInt は第 1 引数である文字列 str をパースし、指定した radix (基数) の整数を返そうとします。radix は省略可能な第 2 引数です。例えば、10 という基数では 10 進数に変換し、8 では 8 進数、16 では 16 進数というように変換します。10 より大きな基数では、アルファベットで 9 より大きい数を表します。例えば 16 進数 (基数 16) では、A から F が使用されます。

    parseInt は指定した基数の数値ではない文字に出くわすと、その文字と後続の文字すべてを無視し、それまでにパースした整数の値を返します。最初の文字を指定した基数の値に変換できない場合は、"NaN" を返します。parseInt は文字列を切り捨てて整数の値にします。

    Number 関数および String 関数

    Number および String 関数は、オブジェクトを数値や文字列に変換します。これらの関数の構文は以下のとおりです:

    var objRef;
    objRef = Number(objRef);
    objRef = String(objRef);
    

    ここで objRef は、オブジェクト参照を表します。Number 関数は、オブジェクトの valueOf() メソッドを用います。String 関数は、オブジェクトの toString() メソッドを用います。

    次の例では、Date オブジェクトを理解できる文字列に変換します。

    var D = new Date(430054663215),
        x;
    x = String(D); // x は "Thu Aug 18 04:37:43 GMT-0700 (Pacific Daylight Time) 1983" と等しい
    

    次の例では、String オブジェクトを Number オブジェクトに変換します。

    var str = "12",
        num;
    num = Number(str);
    

    この結果を確認できます。DOM の write() メソッドと JavaScript の typeof 演算子を使用してください。

    var str = "12",
        num;
    document.write(typeof str);
    document.write("<br/>");
    num = Number(str);
    document.write(typeof num);
    

    escape 関数および unescape 関数

    escape および unescape 関数は非 ASCII 文字に対して適切に動作せず、非推奨になりました。JavaScript 1.5 以降では encodeURIdecodeURIencodeURIComponent、および decodeURIComponent を使用してください。

    escape および unescape 関数は、文字列のエンコードやデコードを行います。escape 関数は ISO Latin 文字セットで表された、引数の 16 進エンコーディングを返します。unescape 関数は、指定した 16 進エンコーディングの値に対する ASCII 文字列を返します。

    これらの関数の構文は以下のとおりです:

    escape(string);
    unescape(string);
    

    これらの関数は、主にサーバサイド JavaScript で URL 中の名前と値のペアのエンコードやデコードに使用されます。

    ドキュメントのタグと貢献者

    Contributors to this page: ethertank, Potappo, yyss, happysadman, Electrolysis
    最終更新者: ethertank,