web-dev-qa-db-ja.com

var functionName = function(){} vs function functionName(){}

私は最近他の誰かのJavaScriptコードを保守し始めました。私はバグを修正し、機能を追加し、さらにコードを整理して一貫性を高めようとしています。

前の開発者は2つの方法で関数を宣言していますが、その理由があるかどうかわからないと解決できません。

2つの方法があります:

var functionOne = function() {
    // Some code
};
function functionTwo() {
    // Some code
}

これら2つの異なる方法を使用する理由は何ですか、またそれぞれの長所と短所は何ですか?ある方法ではできない、他の方法ではできないことがありますか。

6315
Richard Garside

違いは、functionOneは関数式であり、その行に到達したときにのみ定義されるのに対して、functionTwoは関数宣言であり、周囲の関数またはスクリプトが実行されるとすぐに定義されることです( hoisting のため)。 

たとえば、関数式

// TypeError: functionOne is not a function
functionOne();

var functionOne = function() {
  console.log("Hello!");
};

そして、関数宣言: 

// Outputs: "Hello!"
functionTwo();

function functionTwo() {
  console.log("Hello!");
}

これはまた、関数宣言を使って関数を条件付きで定義できないことを意味します。

if (test) {
   // Error or misbehavior
   function functionThree() { doSomething(); }
}

上記は実際にはfunctionThreeの値に関係なくtestを定義します - use strictが有効でない限り、それは単にエラーを発生させます。

4694
Greg

最初にGregを修正します。function abc(){}もスコープ指定されています - abcという名前は、この定義があるスコープ内で定義されています。例:

function xyz(){
  function abc(){};
  // abc is defined here...
}
// ...but not here

次に、両方のスタイルを組み合わせることが可能です。

var xyz = function abc(){};

xyzは通常通りに定義され、abcはすべてのブラウザで未定義ですが、Internet Explorer - 定義されていることに頼らないでください。しかし、それはその本体の中で定義されます。

var xyz = function abc(){
  // xyz is visible here
  // abc is visible here
}
// xyz is visible here
// abc is undefined here

すべてのブラウザで関数のエイリアスを作りたい場合は、次のような宣言を使用してください。

function abc(){};
var xyz = abc;

この場合、xyzabcは同じオブジェクトのエイリアスです。

console.log(xyz === abc); // prints "true"

複合スタイルを使用する説得力のある理由の1つは、機能オブジェクトの "name"属性です( Internet Explorerではサポートされていません )。基本的にあなたがのような関数を定義するとき

function abc(){};
console.log(abc.name); // prints "abc"

その名前は自動的に割り当てられます。しかし、あなたがそれを次のように定義すると

var abc = function(){};
console.log(abc.name); // prints ""

その名前は空です - 私たちは無名関数を作成し、それを何らかの変数に割り当てました。

複合スタイルを使用するもう1つの良い理由は、短い内部名を使用して自分自身を参照する一方で、外部ユーザーには競合しない長い名前を提供することです。

// Assume really.long.external.scoped is {}
really.long.external.scoped.name = function shortcut(n){
  // Let it call itself recursively:
  shortcut(n - 1);
  // ...
  // Let it pass itself as a callback:
  someFunction(shortcut);
  // ...
}

上記の例では、外部の名前でも同じことができますが、扱いにくくなり過ぎます(そして遅くなります)。

(それ自体を参照するもう1つの方法はarguments.calleeを使用することです。これはまだ比較的長く、strictモードではサポートされていません。)

深く、JavaScriptは両方のステートメントを異なる方法で扱います。これは関数宣言です。

function abc(){}

ここでのabcは、現在のスコープ内のあらゆる場所で定義されています。

// We can call it here
abc(); // Works

// Yet, it is defined down there.
function abc(){}

// We can call it again
abc(); // Works

また、それはreturnステートメントを通して掲げられました:

// We can call it here
abc(); // Works
return;
function abc(){}

これは関数式です。

var xyz = function(){};

ここでのxyzは代入の点から定義されます。

// We can't call it here
xyz(); // UNDEFINED!!!

// Now it is defined
xyz = function(){}

// We can call it here
xyz(); // works

関数宣言対関数式が、Gregによって実証された違いがある本当の理由です。

楽しい事実:

var xyz = function abc(){};
console.log(xyz.name); // Prints "abc"

個人的には、「関数式」宣言を好むのは、この方法で可視性を制御できるからです。関数を次のように定義すると

var abc = function(){};

関数をローカルに定義したことを知っています。関数を次のように定義すると

abc = function(){};

スコープチェーンのどこにもabcを定義しないという条件で、私はそれをグローバルに定義したことを知っています。この定義スタイルはeval()の中で使われても弾力的です。定義しながら

function abc(){};

特にeval()の場合、文脈に依存し、それが実際に定義されている場所を推測したままにするかもしれません - 答えはブラウザに依存します。

1853
Eugene Lazutkin

関数を作成する標準フォームの概要は次のとおりです。(元は別の質問用に書かれていますが、正規の質問に移動した後に適合します。)

条項:

クイックリスト:

  • 関数宣言

  • 「匿名」function(この用語にもかかわらず、名前付きの関数を作成する場合があります)

  • 名前付きfunction

  • アクセサー関数初期化子(ES5 +)

  • 矢印関数式(ES2015 +)(匿名関数式と同様に、明示的な名前を含まず、名前を持つ関数を作成できます)

  • オブジェクト初期化子のメソッド宣言(ES2015 +)

  • classのコンストラクターとメソッドの宣言(ES2015 +)

関数宣言

最初の形式は関数宣言で、次のようになります。

function x() {
    console.log('x');
}

関数宣言はdeclaration;です。ステートメントや式ではありません。そのため、;を付けないでください(そうすることは無害です)。

関数宣言は、実行が出現するコンテキストに入ると処理されます。beforeステップバイステップコードが実行されます。作成する関数には適切な名前(上記の例ではx)が与えられ、その名前は宣言が現れるスコープに入れられます。

同じコンテキストでステップバイステップのコードの前に処理されるため、次のようなことができます。

x(); // Works even though it's above the declaration
function x() {
    console.log('x');
}

ES2015まで、仕様では、tryifswitchwhileなどのような制御構造内に関数宣言を配置した場合、JavaScriptエンジンが何を行うべきかについては説明していませんでした。

if (someCondition) {
    function foo() {    // <===== HERE THERE
    }                   // <===== BE DRAGONS
}

そして、それらは処理されるためbeforeステップバイステップのコードが実行されるため、制御構造内にいるときに何をすべきかを知ることはトリッキーです。

これを行うことは指定 ES2015までではありませんでしたが、ブロックでの関数宣言をサポートするための許可される拡張でした。残念ながら(そして必然的に)、異なるエンジンは異なることをしました。

ES2015の時点で、仕様は何をすべきかを示しています。実際、次の3つのことを行う必要があります。

  1. ルースモードnotがWebブラウザーの場合、JavaScriptエンジンは1つのことを行うことになっています。
  2. Webブラウザーでルーズモードの場合、JavaScriptエンジンは別のことを行うことになっています
  3. strictモード(ブラウザかどうか)の場合、JavaScriptエンジンはさらに別のことを行うことになっています

ルーズモードのルールは扱いにくいですが、strictモードでは、ブロック内の関数宣言は簡単です。ブロックに対してローカルです(ブロックスコープがあります。 ES2015の新機能)、ブロックの最上部に引き上げられます。そう:

"use strict";
if (someCondition) {
    foo();               // Works just fine
    function foo() {
    }
}
console.log(typeof foo); // "undefined" (`foo` is not in scope here
                         // because it's not in the same block)

「匿名」function

2番目の一般的な形式は、匿名関数式と呼ばれます。

var y = function () {
    console.log('y');
};

すべての式と同様に、コードの段階的な実行で到達すると評価されます。

ES5では、これが作成する関数には名前がありません(匿名です)。 ES2015では、コンテキストから推測することにより、可能であれば関数に名前が割り当てられます。上記の例では、名前はyになります。関数がプロパティ初期化子の値である場合、同様のことが行われます。 (これがいつ起こるかとルールの詳細については、 仕様 —でSetFunctionNameを検索してください-all over the place。)

名前付きfunction

3番目の形式は名前付き関数式( "NFE")です:

var z = function w() {
    console.log('zw')
};

これが作成する関数には適切な名前(この場合はw)があります。すべての式と同様に、これはコードの段階的な実行で到達すると評価されます。関数の名前はnotであり、式が表示されるスコープに追加されます。関数自体のスコープ内の名前is

var z = function w() {
    console.log(typeof w); // "function"
};
console.log(typeof w);     // "undefined"

NFEはJavaScript実装のバグの原因であることが多いことに注意してください。たとえば、IE8以前では、NFEを処理します 完全に間違っています 、2つの異なる時間に2つの異なる関数を作成します。 Safariの初期バージョンにも問題がありました。幸いなことに、現在のバージョンのブラウザ(IE9以降、現在のSafari)にはこれらの問題はありません。 (しかし、この記事の執筆時点では、残念ながらIE8が広く使用されているため、一般にWebのコードでNFEを使用することには依然として問題があります。)

アクセサー関数初期化子(ES5 +)

機能がほとんど気付かれずに潜入することがあります。 accessor functionsの場合です。以下に例を示します。

var obj = {
    value: 0,
    get f() {
        return this.value;
    },
    set f(v) {
        this.value = v;
    }
};
console.log(obj.f);         // 0
console.log(typeof obj.f);  // "number"

関数を使用したとき、()を使用しなかったことに注意してください。これは、プロパティのaccessor functionであるためです。通常の方法でプロパティを取得および設定しますが、背後で関数が呼び出されます。

Object.definePropertyObject.defineProperties、およびObject.createへのあまり知られていない2番目の引数を使用して、アクセサー関数を作成することもできます。

矢印関数式(ES2015 +)

ES2015は矢印関数をもたらします。次に例を示します。

var a = [1, 2, 3];
var b = a.map(n => n * 2);
console.log(b.join(", ")); // 2, 4, 6

n => n * 2map()呼び出しに隠れていることを確認しますか?それは機能です。

矢印関数に関するいくつかのこと:

  1. 独自のthisはありません。代わりに、close over定義されているコンテキストのthis。 (arguments、および関連する場合はsuperも閉じます。)これは、その中のthisが作成されたthisと同じであり、変更できないことを意味します。

  2. 上記でお気づきのとおり、キーワードfunctionは使用しません。代わりに、=>を使用します。

上記のn => n * 2の例は、それらの1つの形式です。関数を渡す複数の引数がある場合、括弧を使用します。

var a = [1, 2, 3];
var b = a.map((n, i) => n * i);
console.log(b.join(", ")); // 0, 2, 6

Array#mapは、エントリを最初の引数として渡し、インデックスを2番目の引数として渡すことに注意してください。)

どちらの場合も、関数の本体は単なる式です。関数の戻り値は自動的にその式の結果になります(明示的なreturnは使用しません)。

単一の式以上のことをしている場合は、通常どおり、{}と明示的なreturn(値を返す必要がある場合)を使用します。

var a = [
  {first: "Joe", last: "Bloggs"},
  {first: "Albert", last: "Bloggs"},
  {first: "Mary", last: "Albright"}
];
a = a.sort((a, b) => {
  var rv = a.last.localeCompare(b.last);
  if (rv === 0) {
    rv = a.first.localeCompare(b.first);
  }
  return rv;
});
console.log(JSON.stringify(a));

{ ... }のないバージョンは、expression bodyまたはconcise bodyの矢印関数と呼ばれます。 (また:A 簡潔矢印関数。){ ... }が本体を定義するものは、関数本体を持つ矢印関数です。 (また:A verbose arrow関数。)

オブジェクト初期化子のメソッド宣言(ES2015 +)

ES2015では、method definition;と呼ばれる関数を参照するプロパティを宣言する短い形式が許可されています。次のようになります。

var o = {
    foo() {
    }
};

eS5以前でほぼ同等のものは次のようになります。

var o = {
    foo: function foo() {
    }
};

違い(冗長性以外)は、メソッドはsuperを使用できますが、関数は使用できないことです。したがって、たとえば、メソッド構文を使用して(たとえば)valueOfを定義したオブジェクトがある場合、Object.prototype.valueOfが返す値を取得するためにsuper.valueOf()を使用できます(おそらく他の何かを行う前に) ES5バージョンでは、代わりにObject.prototype.valueOf.call(this)を実行する必要があります。

また、メソッドには定義されたオブジェクトへの参照があるため、そのオブジェクトが一時的な場合(たとえば、ソースオブジェクトの1つとしてObject.assignに渡す場合)、メソッド構文- couldは、オブジェクトがガベージコレクションされる可能性がある場合にメモリに保持されることを意味します(JavaScriptエンジンがその状況を検出せず、メソッドがsuperを使用しない場合は処理します)。

classのコンストラクターとメソッドの宣言(ES2015 +)

ES2015は、宣言されたコンストラクターとメソッドを含むclass構文を提供します。

class Person {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    getFullName() {
        return this.firstName + " " + this.lastName;
    }
}

上記の2つの関数宣言があります。1つは名前Personを取得するコンストラクター用、もう1つはPerson.prototypeに割り当てられた関数であるgetFullName用です。

599
T.J. Crowder

グローバルコンテキストについて言えば、最後のvarステートメントとFunctionDeclarationは両方ともグローバルオブジェクトに削除不可プロパティを作成しますが、両方の値は{上書き可能} _です。

2つの方法の微妙な違いは、 Variable Instantiation プロセスが実行されると(実際のコード実行の前に)varで宣言されたすべての識別子はundefinedで初期化され、FunctionDeclarationで使用される識別子はその時点から使用できる、 例えば:

 alert(typeof foo); // 'function', it's already available
 alert(typeof bar); // 'undefined'
 function foo () {}
 var bar = function () {};
 alert(typeof bar); // 'function'

barFunctionExpressionの割り当ては実行時まで行われます。

FunctionDeclarationによって作成されたグローバルプロパティは、変数値のように問題なく上書きできます。

 function test () {}
 test = null;

2つの例のもう1つの明らかな違いは、最初の関数には名前がありませんが、2番目の関数には名前があることです。これはデバッグ時(つまり呼び出しスタックの検査時)に非常に便利です。

最初の編集例(foo = function() { alert('hello!'); };)については、宣言されていない割り当てです。常にvarキーワードを使用することを強くお勧めします。

代入では、varステートメントを使用せずに、参照された識別子がスコープチェーンに見つからない場合、それはグローバルオブジェクトの削除可能プロパティになります。

また、宣言されていない代入はECMAScript 5の Strict Mode の下でReferenceErrorをスローします。

必読:

:この答えは 他の質問 からマージされています。この質問では、OPからの大きな疑問と誤解はFunctionDeclarationで宣言された識別子を上書きできないということでした。

138
CMS

ここに投稿した2つのコードスニペットは、ほぼすべての目的で同じように動作します。

ただし、動作の違いは、最初のバリアント(var functionOne = function() {})では、その関数はコード内のその時点以降にしか呼び出せないことです。

2番目のバリエーション(function functionTwo())では、関数は、宣言された場所より上で実行されるコードで使用できます。

これは、最初のバリアントでは、実行時に関数が変数fooに割り当てられるためです。 2番目の関数では、解析時に関数がその識別子fooに割り当てられます。

もっと技術的な情報

JavaScriptには関数を定義する3つの方法があります。

  1. 最初のスニペットは 関数式 を示しています。これには、 "function"演算子 を使用して関数を作成することが含まれます。その演算子の結果は、任意の変数またはオブジェクトプロパティに格納できます。関数式はそのように強力です。関数式は名前を持つ必要がないので、しばしば「無名関数」と呼ばれます。
  2. あなたの2番目の例は 関数宣言 です。これは "function"ステートメント を使用して関数を作成します。この関数は解析時に利用可能になり、そのスコープ内の任意の場所で呼び出すことができます。後で変数やオブジェクトのプロパティに保存することもできます。
  3. 関数を定義する3つ目の方法は "Function()"コンストラクタ です。これは元の投稿には表示されていません。問題があるeval()と同じように機能するので、これを使用することはお勧めできません。
116
thomasrutter

グレッグの答えへのより良い説明

functionTwo();
function functionTwo() {
}

なぜエラーがないのか式は上から下に実行されることを常に教えられてきました(??)

なぜなら

関数宣言と変数宣言は、JavaScriptインタプリタによって常に見えないようにそれらの包含スコープの先頭に移動(hoisted)します。関数パラメータと言語定義の名前は、明らかにすでに存在しています。 ベンチェリー

これは次のようなコードを意味します。

functionOne();                  ---------------      var functionOne;
                                | is actually |      functionOne();
var functionOne = function(){   | interpreted |-->
};                              |    like     |      functionOne = function(){
                                ---------------      };

宣言の代入部分が引き上げられていないことに注意してください。名前だけが掲げられています。

ただし、関数宣言の場合は、関数本体全体も同様に引き上げられます

functionTwo();              ---------------      function functionTwo() {
                            | is actually |      };
function functionTwo() {    | interpreted |-->
}                           |    like     |      functionTwo();
                            ---------------
97
simple_human

他のコメンターはすでに上記の2つの異形の意味の違いをカバーしています。私はスタイルの違いに注目したいと思いました: "割り当て"バリエーションだけが他のオブジェクトのプロパティを設定することができます。

私はよく次のようなパターンでJavaScriptモジュールを構築します。

(function(){
    var exports = {};

    function privateUtil() {
            ...
    }

    exports.publicUtil = function() {
            ...
    };

    return exports;
})();

このパターンでは、パブリック関数はすべて代入を使用し、プライベート関数は宣言を使用します。

(また、代入では文の後にセミコロンが必要ですが、宣言では禁止されています)。

88
Sean McMillan

最初の方法を2番目の方法よりも優先する場合の例は、関数の以前の定義をオーバーライドしないようにする必要がある場合です。

あり

if (condition){
    function myfunction(){
        // Some code
    }
}

myfunctionのこの定義は、解析時に行われるため、以前の定義をオーバーライドします。

しながら

if (condition){
    var myfunction = function (){
        // Some code
    }
}

myfunctionが定義されている場合にのみconditionを定義する正しい仕事をします。

74
Mbengue Assane

重要な理由は、あなたの名前空間の "Root"としてただ一つの変数を追加することです...

var MyNamespace = {}
MyNamespace.foo= function() {

}

または

var MyNamespace = {
  foo: function() {
  },
  ...
}

名前空間の付け方はたくさんあります。たくさんのJavaScriptモジュールが利用可能になったことで、より重要になります。

もご覧ください。JavaScriptで名前空間を宣言するにはどうすればよいですか。

60
Rob

Hoistingは、すべての変数と関数の宣言を現在のスコープの先頭に移動するというJavaScriptインタプリタの動作です。 

ただし、実際の宣言のみが掲げられています。割り当てをそのままにします。

  • ページ内で宣言された変数/関数はグローバルであり、そのページ内の任意の場所にアクセスできます。
  • 関数内で宣言された変数の/関数はローカルスコープを持ちます。関数本体(スコープ)内で利用可能/アクセス可能であることを意味します。関数本体外では利用できません。

変数

Javascriptは緩やかに型付けされた言語と呼ばれています。つまり、JavaScript変数は任意の Data-Typeの値を保持できます。 Javascriptは実行時に提供された値/リテラル​​に基づいて変数タイプを自動的に変更します。

global_Page = 10;                                               var global_Page;      « undefined
    « Integer literal, Number Type.   -------------------       global_Page = 10;     « Number         
global_Page = 'Yash';                 |   Interpreted   |       global_Page = 'Yash'; « String
    « String literal, String Type.    «       AS        «       global_Page = true;   « Boolean 
var global_Page = true;               |                 |       global_Page = function (){          « function
    « Boolean Type                    -------------------                 var local_functionblock;  « undefined
global_Page = function (){                                                local_functionblock = 777;« Number
    var local_functionblock = 777;                              };  
    // Assigning function as a data.
};  

関数

function Identifier_opt ( FormalParameterList_opt ) { 
      FunctionBody | sequence of statements

      « return;  Default undefined
      « return 'some data';
}
  • ページ内で宣言された関数は、グローバルアクセス権を持つページの先頭に配置されます。
  • function-block内で宣言された関数は、そのブロックの先頭に配置されます。
  • 関数のデフォルトの戻り値は ' undefined '、 Variable 宣言のデフォルト値も 'undefined'です。

    Scope with respect to function-block global. 
    Scope with respect to page undefined | not available.
    

関数宣言

function globalAccess() {                                  function globalAccess() {      
}                                  -------------------     }
globalAccess();                    |                 |     function globalAccess() { « Re-Defined / overridden.
localAccess();                     «   Hoisted  As   «         function localAccess() {
function globalAccess() {          |                 |         }
     localAccess();                -------------------         localAccess(); « function accessed with in globalAccess() only.
     function localAccess() {                              }
     }                                                     globalAccess();
}                                                          localAccess(); « ReferenceError as the function is not defined

関数式

        10;                 « literal
       (10);                « Expression                (10).toString() -> '10'
var a;                      
    a = 10;                 « Expression var              a.toString()  -> '10'
(function invoke() {        « Expression Function
 console.log('Self Invoking');                      (function () {
});                                                               }) () -> 'Self Invoking'

var f; 
    f = function (){        « Expression var Function
    console.log('var Function');                                   f ()  -> 'var Function'
    };

変数に割り当てられた関数例:

(function selfExecuting(){
    console.log('IIFE - Immediately-Invoked Function Expression');
}());

var anonymous = function (){
    console.log('anonymous function Expression');
};

var namedExpression = function for_InternalUSE(fact){
    if(fact === 1){
        return 1;
    }

    var localExpression = function(){
        console.log('Local to the parent Function Scope');
    };
    globalExpression = function(){ 
        console.log('creates a new global variable, then assigned this function.');
    };

    //return; //undefined.
    return fact * for_InternalUSE( fact - 1);   
};

namedExpression();
globalExpression();

javaScriptは次のように解釈されます

var anonymous;
var namedExpression;
var globalExpression;

anonymous = function (){
    console.log('anonymous function Expression');
};

namedExpression = function for_InternalUSE(fact){
    var localExpression;

    if(fact === 1){
        return 1;
    }
    localExpression = function(){
        console.log('Local to the parent Function Scope');
    };
    globalExpression = function(){ 
        console.log('creates a new global variable, then assigned this function.');
    };

    return fact * for_InternalUSE( fact - 1);    // DEFAULT UNDEFINED.
};

namedExpression(10);
globalExpression();

あなたは jsperf Test Runner を使って異なるブラウザの上で関数宣言、式テストをチェックすることができます


ES5コンストラクタ関数クラス :Function.prototype.bindで作成した関数オブジェクト

JavaScriptは関数をファーストクラスのオブジェクトとして扱うので、オブジェクトであるため、関数にプロパティを割り当てることができます。

function Shape(id) { // Function Declaration
    this.id = id;
};
    // Adding a prototyped method to a function.
    Shape.prototype.getID = function () {
        return this.id;
    };
    Shape.prototype.setID = function ( id ) {
        this.id = id;
    };

var expFn = Shape; // Function Expression

var funObj = new Shape( ); // Function Object
funObj.hasOwnProperty('prototype'); // false
funObj.setID( 10 );
console.log( funObj.getID() ); // 10

ES6が導入されました Arrow function :arrow function式は、より短い構文を持ち、メソッド以外の関数に最も適しており、コンストラクタとしては使用できません。

ArrowFunction : ArrowParameters => ConciseBody

const fn = (item) => { return item & 1 ? 'Odd' : 'Even'; };
console.log( fn(2) ); // Even
console.log( fn(3) ); // Odd
52
Yash

他のみんなが巻き上げ部分を徹底的にカバーしたからといって、私は私自身の答えを加えています。

私は今のところどの方法がずっと良いのか疑問に思いました、そしておかげで http://jsperf.com 今私は知っています:)

enter image description here

関数宣言 は速いです、そしてそれはWeb開発者にとって本当に重要なことなのですか? ;)

36
Leon Gaban

バインディングが確立されると、関数宣言と変数に割り当てられた関数式は同じように動作します。

ただし、howwhenには違いがあります。関数オブジェクトは実際にはその変数に関連付けられています。この違いは、JavaScriptのvariable hoistingというメカニズムによるものです。

基本的に、すべての関数宣言と変数宣言は、宣言が行われるfunctionの先頭に配置されています(これが、JavaScriptがfunction scopeを持つ理由です)。

  • 関数宣言が持ち上げられると、関数本体はに「従います」ので、関数本体が評価されると、変数はすぐに関数オブジェクトにバインドされます。

  • 変数宣言が持ち上げられると、初期化はnot に従いますが、「取り残された」ままです。変数は、関数本体の先頭で undefinedに初期化され、assigned のコード内の元の位置の値になります。 (実際には、同じ名前の変数の宣言が行われるeveryの位置に値が割り当てられます。)

巻き上げの順序も重要です。関数宣言は同じ名前の変数宣言よりも優先され、最後の関数宣言は同じ名前の前の関数宣言よりも優先されます。

いくつかの例...

var foo = 1;
function bar() {
  if (!foo) {
    var foo = 10 }
  return foo; }
bar() // 10

変数fooは関数の先頭に持ち上げられ、undefinedに初期化されるので、!footrueになり、fooには10が割り当てられます。 fooのスコープ外のbarは何の役割も果たさずそのままです。 

function f() {
  return a; 
  function a() {return 1}; 
  var a = 4;
  function a() {return 2}}
f()() // 2

function f() {
  return a;
  var a = 4;
  function a() {return 1};
  function a() {return 2}}
f()() // 2

関数宣言は変数宣言よりも優先され、最後の関数宣言は「固執」します。

function f() {
  var a = 4;
  function a() {return 1}; 
  function a() {return 2}; 
  return a; }
f() // 4

この例では、aは2番目の関数宣言を評価した結果の関数オブジェクトで初期化され、その後4が割り当てられています。

var a = 1;
function b() {
  a = 10;
  return;
  function a() {}}
b();
a // 1

ここでは関数宣言が最初に持ち上げられ、変数aを宣言して初期化します。次に、この変数に10を割り当てます。言い換えると、代入は外部変数aに代入しません。

32
eljenso

最初の例は関数宣言です。

function abc(){}

2番目の例は関数式です。

var abc = function() {};

主な違いは、それらがどのように吊り上げられるか(持ち上げられ宣言される)です。最初の例では、関数宣言全体がまとめられています。 2番目の例では、var 'abc'だけが持ち上げられ、その値(関数)は未定義になり、関数自体は宣言された位置に残ります。

簡単に言えば:

//this will work
abc(param);
function abc(){}

//this would fail
abc(param);
var abc = function() {}

このトピックについてもっと学ぶために、私はあなたにこれを強く勧めます link

30
sla55er

コード保守コストの観点からは、名前付き関数がより好ましいです。

  • 宣言されている場所からは独立しています(ただし、まだ範囲によって制限されています)。
  • 条件付き初期化のような間違いに対してより耐性があります(必要であれば上書きすることができます)。
  • スコープ機能とは別にローカル関数を割り当てることで、コードが読みやすくなります。通常、スコープ内で機能が最初になり、その後にローカル関数の宣言が続きます。
  • デバッガでは、「匿名/評価済み」関数の代わりに、呼び出しスタックに関数名がはっきりと表示されます。

名前付き関数のためのもっと多くのPROSが続くのではないかと思います。そして、名前付き関数の利点として挙げられていることは、無名関数にとっては不利です。

歴史的に、無名関数は、名前付き関数を持つメンバーをリストするための言語としてのJavaScriptの無力から現れました。

{
    member:function() { /* How do I make "this.member" a named function? */
    }
}
28
Sasha Firsov

私は自分のコードで可変的なアプローチを非常に具体的な理由で使用していますが、その理論は上で抽象的な方法でカバーされていますが、JavaScriptの専門知識が限られています。

私は160個の独立したデザインのブランディングで実行する必要があるコードを持っています。コードの大部分は共有ファイルにありますが、ブランド固有のものは、ブランドごとに1つの別々のファイルにあります。

特定の機能を必要とするブランドもあれば、そうでないブランドもあります。新しいブランド特有のことをするために新しい機能を追加しなければならないことがあります。共有コードを変更できてうれしいですが、160セットのブランドファイルすべてを変更する必要はありません。

変数構文を使用することで、共有コード内で変数(本質的には関数ポインタ)を宣言し、簡単なスタブ関数を割り当てるか、またはnullに設定することができます。

関数の特定の実装を必要とする1つまたは2つのブランドは、その関数のバージョンを定義し、必要に応じてこれを変数に割り当てることができ、残りは何もしません。共有コードで実行する前に、null関数をテストできます。

上記の人々のコメントから、私は静的関数も再定義することが可能かもしれないと私は集めるが、私は変数の解決策が素晴らしく明確であると思う。

24
Herc

コンピュータサイエンスの用語では、無名関数と名前付き関数について説明します。最も重要な違いは、無名関数は名前にバインドされていないということです。つまり、無名関数という名前です。 JavaScriptでは、実行時に動的に宣言されるファーストクラスオブジェクトです。

匿名関数とラムダ計算の詳細については、Wikipediaをお勧めします( http://en.wikipedia.org/wiki/Anonymous_function )。

22
Kafka

Greg's Answer は十分ですが、 Douglas Crockfordの を見ていたので、まだ追加したいと思います。

関数式:

var foo = function foo() {};

機能ステートメント:

function foo() {};

Functionステートメントは、var値を持つfunctionステートメントの単なる略記です。

そう

function foo() {};

に展開

var foo = function foo() {};

これはさらに拡張されます。

var foo = undefined;
foo = function foo() {};

そして、どちらもコードの先頭に掲げられています。

Screenshot from video

22
Rohan

@EugeneLazutkin は自分自身への内部参照として shortcut() を使うことができるように割り当てられた関数を指定します。 John Resig は別の例を挙げます - 彼の Learning Advanced Javascript チュートリアルで他のオブジェクトに割り当てられた再帰関数をコピーする。ここでは関数にプロパティを割り当てることは厳密には問題ではありませんが、私は積極的にチュートリアルを試してみることをお勧めします - 右上隅のボタンをクリックしてコードを実行し、好みに合わせてコードをダブルクリックします。

チュートリアルの例:yell()内の再帰呼び出し:

元の忍者オブジェクトが削除されるとテストは失敗します。 (13ページ)

var ninja = { 
  yell: function(n){ 
    return n > 0 ? ninja.yell(n-1) + "a" : "hiy"; 
  } 
}; 
assert( ninja.yell(4) == "hiyaaaa", "A single object isn't too bad, either." ); 

var samurai = { yell: ninja.yell }; 
var ninja = null; 

try { 
  samurai.yell(4); 
} catch(e){ 
  assert( false, "Uh, this isn't good! Where'd ninja.yell go?" ); 
}

再帰的に呼び出される関数に名前を付けると、テストに合格します。 (14ページ)

var ninja = { 
  yell: function yell(n){ 
    return n > 0 ? yell(n-1) + "a" : "hiy"; 
  } 
}; 
assert( ninja.yell(4) == "hiyaaaa", "Works as we would expect it to!" ); 

var samurai = { yell: ninja.yell }; 
var ninja = {}; 
assert( samurai.yell(4) == "hiyaaaa", "The method correctly calls itself." );
18
Joel Purra

他の答えで言及されていないもう一つの違いはあなたが無名関数を使用する場合です。

var functionOne = function() {
    // Some code
};

そしてそれをコンストラクタとして使用する

var one = new functionOne();

one.constructor.nameは定義されません。 Function.nameは非標準ですが、Firefox、Chrome、他のWebkit由来のブラウザ、およびIE 9+でサポートされています。

あり 

function functionTwo() {
    // Some code
}
two = new functionTwo();

two.constructor.nameを使用してコンストラクタの名前を文字列として取得することは可能です。

16
Ingo Kegel

最初のもの(関数doSomething(x))はオブジェクト表記法の一部であるべきです。

2番目のもの(var doSomething = function(x){ alert(x);})は、単純に無名関数を作成してそれを変数doSomethingに割り当てることです。そのため、doSomething()は関数を呼び出します。

関数宣言 および 関数式 が何であるかを知りたいと思うかもしれません。

関数宣言は、変数の割り当てを必要とせずに名前付き関数変数を定義します。関数宣言は独立した構成要素として行われ、非関数ブロック内にネストすることはできません。

function foo() {
    return 3;
}

ECMA 5(13.0)では、構文は次のように定義されています。 
関数識別子(FormalParameterListopt ){FunctionBody}

上記の条件では、関数名はその有効範囲とその親の有効範囲内に表示されます(そうでなければ到達できません)。

そして関数式の中で

関数式は、より大きな式の構文の一部として関数を定義します(通常は変数代入)。関数式によって定義された関数は、名前付きまたは匿名にすることができます。関数式は「function」で始まってはいけません。

// Anonymous function expression
var a = function() {
    return 3;
}

// Named function expression
var a = function foo() {
    return 3;
}

// Self-invoking function expression
(function foo() {
    alert("hello!");
})();

ECMA 5(13.0)では、構文は次のように定義されています。 
機能識別子opt (FormalParameterListopt ){FunctionBody}

14
NullPoiиteя

これらの関数を使ってオブジェクトを作成すると、次のようになります。

var objectOne = new functionOne();
console.log(objectOne.__proto__); // prints "Object {}" because constructor is an anonymous function

var objectTwo = new functionTwo();
console.log(objectTwo.__proto__); // prints "functionTwo {}" because constructor is a named function
14
Pawel Furmaniak

私は以下の違いを挙げています:

  1. 関数宣言はコード内の任意の場所に配置できます。定義がコードに表示される前に呼び出された場合でも、ページ内の他のコードが実行を開始する前に、関数宣言がメモリにコミットされるとき、または起動されるときに実行されます。

    以下の機能を見てください。

    function outerFunction() {
        function foo() {
           return 1;
        }
        return foo();
        function foo() {
           return 2;
        }
    }
    alert(outerFunction()); // Displays 2
    

    これは、実行中、次のように見えるためです。 -

    function foo() {  // The first function declaration is moved to top
        return 1;
    }
    function foo() {  // The second function declaration is moved to top
        return 2;
    }
    function outerFunction() {
        return foo();
    }
    alert(outerFunction()); //So executing from top to bottom,
                            //the last foo() returns 2 which gets displayed
    

    関数式を呼び出す前に定義されていないと、エラーになります。また、ここでは関数定義自体が先頭に移動されたり、関数宣言のようにメモリにコミットされたりすることはありません。しかし、関数に割り当てた変数は起動され、 undefined に割り当てられます。

    関数式を使った同じ関数

    function outerFunction() {
        var foo = function() {
           return 1;
        }
        return foo();
        var foo = function() {
           return 2;
        }
    }
    alert(outerFunction()); // Displays 1
    

    これは、実行中は次のようになるためです。

    function outerFunction() {
       var foo = undefined;
       var foo = undefined;
    
       foo = function() {
          return 1;
       };
       return foo ();
       foo = function() {   // This function expression is not reachable
          return 2;
       };
    }
    alert(outerFunction()); // Displays 1
    
  2. アクセスできないため、 if のように非ファンクションブロックにファンクション宣言を記述するのは安全ではありません。

    if (test) {
        function x() { doSomething(); }
    }
    
  3. 以下のような名前付き関数式は、バージョン9より前のInternet Explorerブラウザでは機能しない可能性があります。

    var today = function today() {return new Date()}
    
14
varna

「名前付き関数はスタックトレースに現れる」という議論に照らして、現代のJavaScriptエンジンは実際には無名関数を表現する能力がかなりあります。

これを書いている時点では、V8、SpiderMonkey、Chakra、Nitroは常に名前付き関数をそれらの名前で参照しています。ほとんどの場合、無名関数を持っていれば、その名前で無名関数を参照します。

SpiderMonkeyは他の関数から返された無名関数の名前を知ることができます。残りはできません。

あなたが本当に、本当にあなたのイテレータと成功のコールバックがトレースに現れることを望んでいたならば、あなたもそれらに名前を付けることができます...

[].forEach(function iterator() {});

しかし、ほとんどの場合、それは強調する価値がありません。

ハーネス( Fiddle

'use strict';

var a = function () {
    throw new Error();
},
    b = function b() {
        throw new Error();
    },
    c = function d() {
        throw new Error();
    },
    e = {
        f: a,
        g: b,
        h: c,
        i: function () {
            throw new Error();
        },
        j: function j() {
            throw new Error();
        },
        k: function l() {
            throw new Error();
        }
    },
    m = (function () {
        return function () {
            throw new Error();
        };
    }()),
    n = (function () {
        return function n() {
            throw new Error();
        };
    }()),
    o = (function () {
        return function p() {
            throw new Error();
        };
    }());

console.log([a, b, c].concat(Object.keys(e).reduce(function (values, key) {
    return values.concat(e[key]);
}, [])).concat([m, n, o]).reduce(function (logs, func) {

    try {
        func();
    } catch (error) {
        return logs.concat('func.name: ' + func.name + '\n' +
                           'Trace:\n' +
                           error.stack);
        // Need to manually log the error object in Nitro.
    }

}, []).join('\n\n'));

V8

func.name: 
Trace:
Error
    at a (http://localhost:8000/test.js:4:11)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: b
Trace:
Error
    at b (http://localhost:8000/test.js:7:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: d
Trace:
Error
    at d (http://localhost:8000/test.js:10:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at a (http://localhost:8000/test.js:4:11)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: b
Trace:
Error
    at b (http://localhost:8000/test.js:7:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: d
Trace:
Error
    at d (http://localhost:8000/test.js:10:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at e.i (http://localhost:8000/test.js:17:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: j
Trace:
Error
    at j (http://localhost:8000/test.js:20:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: l
Trace:
Error
    at l (http://localhost:8000/test.js:23:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at http://localhost:8000/test.js:28:19
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: n
Trace:
Error
    at n (http://localhost:8000/test.js:33:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: p
Trace:
Error
    at p (http://localhost:8000/test.js:38:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27 test.js:42

クモザル

func.name: 
Trace:
a@http://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: b
Trace:
b@http://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: d
Trace:
d@http://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
a@http://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: b
Trace:
b@http://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: d
Trace:
d@http://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
e.i@http://localhost:8000/test.js:17:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: j
Trace:
j@http://localhost:8000/test.js:20:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: l
Trace:
l@http://localhost:8000/test.js:23:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
m</<@http://localhost:8000/test.js:28:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: n
Trace:
n@http://localhost:8000/test.js:33:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: p
Trace:
p@http://localhost:8000/test.js:38:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1

チャクラ

func.name: undefined
Trace:
Error
   at a (http://localhost:8000/test.js:4:5)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at b (http://localhost:8000/test.js:7:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at d (http://localhost:8000/test.js:10:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at a (http://localhost:8000/test.js:4:5)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at b (http://localhost:8000/test.js:7:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at d (http://localhost:8000/test.js:10:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at e.i (http://localhost:8000/test.js:17:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at j (http://localhost:8000/test.js:20:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at l (http://localhost:8000/test.js:23:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at Anonymous function (http://localhost:8000/test.js:28:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at n (http://localhost:8000/test.js:33:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at p (http://localhost:8000/test.js:38:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)

ニトロ

func.name: 
Trace:
a@http://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: b
Trace:
b@http://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: d
Trace:
d@http://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
a@http://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: b
Trace:
b@http://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: d
Trace:
d@http://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
i@http://localhost:8000/test.js:17:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: j
Trace:
j@http://localhost:8000/test.js:20:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: l
Trace:
l@http://localhost:8000/test.js:23:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
http://localhost:8000/test.js:28:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: n
Trace:
n@http://localhost:8000/test.js:33:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: p
Trace:
p@http://localhost:8000/test.js:38:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
12
Jackson

以下にリストされているように、2つの異なる関数宣言の間には4つの注目すべき比較があります。 

  1. 機能の可用性(スコープ)

function add()は最も近いブロックにスコープされているので、次のように動作します。

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

function add(a, b){
  return a + b;
}

以下は機能しません(var add=function add()を置き換えたため)。

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

var add=function add(a, b){
  return a + b;
}

addは使用後に宣言されるため、以下は機能しません。

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

var add=function(a, b){
  return a + b;
}

  1. (関数) 。name

このように宣言された場合、関数の名前function thefuncname(){} thefuncname です。

function foobar(a, b){}

console.log(foobar.name);

var a = function foobar(){};

console.log(a.name);

そうではなく、関数がfunction(){}として宣言されている場合、 function 。nameが関数を格納するために使用される最初の変数です。

var a = function(){};
var b = (function(){ return function(){} });

console.log(a.name);
console.log(b.name);

関数に変数が設定されていない場合、関数名は空の文字列("")です。

console.log((function(){}).name === "");

最後に、関数が割り当てられた変数が最初に名前を設定しますが、関数に設定された連続した変数は名前を変更しません。

var a = function(){};
var b = a;
var c = b;

console.log(a.name);
console.log(b.name);
console.log(c.name);

  1. パフォーマンス

GoogleのV8とFirefoxのSpidermonkeyでは、数マイクロ秒のJISTコンパイルの違いがあるかもしれませんが、最終的には結果はまったく同じです。これを証明するために、2つの空白コードスニペットの速度を比較することによって、マイクロベンチマークでのJSPerfの効率を調べてみましょう。 JSPerfテストはこちら にあります。そして、 jsben.chテストがここにあります 。ご覧のとおり、存在しないはずの場合は顕著な違いがあります。もしあなたが私のように本当にパフォーマンスが悪いのであれば、スコープ内の変数や関数の数を減らし、特に多相(2つの異なる型を格納するために同じ変数を使うなど)を排除しようとするとより価値があります。

  1. 可変ミュータビリティ

変数を宣言するためにvarキーワードを使用すると、そのように変数に別の値を再割り当てすることができます。

(function(){
    "use strict";
    var foobar = function(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

しかし、constステートメントを使用すると、変数参照は不変になります。つまり、変数に新しい値を代入することはできません。ただし、これによって変数の内容が不変になるわけではありません。const arr = []を実行しても、arr[10] = "example"を実行できます。 arr = "new value"arr = []のようなことをするだけで、以下のようにエラーが発生します。

(function(){
    "use strict";
    const foobar = function(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

興味深いことに、変数をfunction funcName(){}として宣言した場合、変数の不変性はvarで宣言した場合と同じになります。

(function(){
    "use strict";
    function foobar(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

「最も近いブロック」とは

「最近接ブロック」は、最も近い「関数」です(非同期関数、ジェネレータ関数、および非同期ジェネレータ関数を含みます)。しかし、興味深いことに、function functionName() {}は、クロージャの外側の項目に対する非クロージャブロックの中では、var functionName = function() {}のように振る舞います。観察する。

  • 通常のvar add=function(){}

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}');
  }
} catch(e) {
  console.log("Is a block");
}
var add=function(a, b){return a + b}

  • 通常のfunction add(){}

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
function add(a, b){
  return a + b;
}

  • 関数

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(function () {
    function add(a, b){
      return a + b;
    }
})();

  • ステートメント(ifelseforwhiletry/catchfinallyswitch/dowhilewith

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
{
    function add(a, b){
      return a + b;
    }
}

  • var add=function()の付いた矢印関数

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(() => {
    var add=function(a, b){
      return a + b;
    }
})();

  • function add()の付いた矢印関数

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(() => {
    function add(a, b){
      return a + b;
    }
})();

11
Jack Giffin

JavaScriptでは、関数を作成する方法は2つあります。

  1. 関数宣言:

    function fn(){
      console.log("Hello");
    }
    fn();
    

    これは非常に基本的でわかりやすいもので、多くの言語で使用されており、C言語ファミリでは標準的なものです。関数を定義し、それを呼び出すことによって実行しました。

    知っておくべきことは、関数は実際にはJavaScriptのオブジェクトであるということです。内部的には上記の関数のオブジェクトを作成し、それにfnという名前を付けるか、オブジェクトへの参照をfnに格納します。関数はJavaScriptのオブジェクトです。関数のインスタンスは実際にはオブジェクトインスタンスです。

  2. 関数式:

    var fn=function(){
      console.log("Hello");
    }
    fn();
    

    JavaScriptにはファーストクラスの関数があります。つまり、文字列または数値を作成してそれを変数に割り当てるのと同じように、関数を作成してそれを変数に割り当てます。ここで、fn変数は関数に割り当てられています。この概念の理由は、関数はJavaScriptのオブジェクトだからです。 fnは上記の関数のオブジェクトインスタンスを指しています。関数を初期化して変数に代入しました。関数を実行して結果を代入するのではありません。

参照:JavaScript関数宣言の構文:var fn = function(){} vs function fn(){}

10
Anoop Rai

どちらも関数の定義方法が異なります。違いは、ブラウザがそれらを解釈して実行コンテキストに読み込む方法です。 

最初のケースは、インタプリタがそのコード行に到達したときにのみロードされる関数式です。したがって、次のようにすると、 functionOneは関数 ではないというエラーが発生します。

functionOne();
var functionOne = function() {
    // Some code
};

その理由は、最初の行でfunctionOneに値が割り当てられていないため、未定義のためです。これを関数として呼び出そうとしているため、エラーが発生しています。

2行目では、無名関数の参照をfunctionOneに代入しています。

2番目のケースは、コードが実行される前にロードされる関数宣言です。したがって、次のようにしても、コードの実行前に宣言が読み込まれるため、エラーにはなりません。

functionOne();
function functionOne() {
   // Some code
}
8
Nitin9791

パフォーマンスについて

新しいバージョンのV8では、いくつかの内部最適化が導入され、SpiderMonkeyも導入されました。

式と宣言の間にはほとんど違いはありません。 
関数式 の方が速いようです now。

Chrome 62.0.3202Chrome test

FireFox 55Firefox test

Chrome Canary 63.0.3225Chrome Canary test


Anonymous関数式 Named関数式に対してより良いパフォーマンス を持つようです.


FirefoxFirefox named_anonymous Chrome CanaryChrome canary named_anonymous ChromeChrome named_anonymous

8
Panos Kal.

最初のものは無名関数に割り当てられた変数(関数宣言)で、2番目はJavaScriptで関数を作成する通常の方法(無名関数宣言)です。 :

1.関数式

var functionOne = function() {
    // Some code
};

関数式は、より大きな式の構文の一部として関数を定義します(通常は変数代入)。関数式で定義された関数は、名前付きまたは匿名のどちらでもかまいません。関数式は、 "function"で始めることはできません(したがって、以下の自己呼び出しの例を囲む括弧)。

JavaScriptの関数はホイストすることができますが、変数は関数にアクセスする前に宣言する必要がありますが、変数にアクセスする前に呼び出すことができます。宣言されている場所の前でその関数にアクセスする、それはあなたがあなたの関数を書く方法であるかもしれません。他の関数を返す関数に対しては、この種の宣言は意味をなさないでしょう。無名関数を呼び出すために使用することもできます。この宣言方法は、JavaScriptでコンストラクタ関数を作成するためのより良い方法です。

2.関数宣言

function functionTwo() {
    // Some code
}

関数宣言は、変数割り当てを必要とせずに名前付き関数変数を定義します。関数宣言はスタンドアロン構造として発生し、非関数ブロック内にネストすることはできません。それらを変数宣言の兄弟として考えることは有用です。 “ var”、Function 宣言は“ function”で始めなければなりません。

これはJavaScriptで関数を呼び出す通常の方法です。JavaScriptのように宣言する前にこの関数を呼び出すこともできますが、すべての関数がHoistedになる場合は、期待どおりにHoistが使用されません。行が大きくなく、コンストラクタ関数でもない通常の関数をすべて呼び出すため。

また、JavaScriptでのホイストのしくみについての詳細情報が必要な場合は、以下のリンクにアクセスしてください。

https://developer.mozilla.org/en-US/docs/Glossary/Hoisting

7
Alireza

これは、関数を宣言する2つの方法にすぎません。2番目の方法では、宣言の前に関数を使用できます。

5
Tao

new Function()は、関数の本体を文字列で渡すために使用できます。したがって、これを使って動的関数を作成することができます。スクリプトを実行せずにスクリプトを渡します。

var func = new Function("x", "y", "return x*y;");
function secondFunction(){
   var result;
   result = func(10,20);
   console.log ( result );
}

secondFunction()
4
SuperNova

これは関数式と呼ばれます。

var getRectArea = function(width, height) {
    return width * height;
};

console.log("Area of Rectangle: " + getRectArea(3,4));
// This should return the following result in the console: 
// Area of Rectangle: 12

これは関数宣言と呼ばれます。

var w = 5;
var h = 6;

function RectArea(width, height) {  //declaring the function
  return area = width * height;
}                                   //note you do not need ; after }

RectArea(w,h);                      //calling or executing the function
console.log("Area of Rectangle: " + area);
// This should return the following result in the console: 
// Area of Rectangle: 30

これが、関数式と関数宣言の違い、およびそれらの使用方法の説明に役立つことを願っています。ありがとう。

1
Kean Amaral

差分関数宣言と関数式:

Javascriptにはファーストクラスの機能があります。これは、他の変数と同様に扱うことができることを意味します。関数は、関数の引数として渡すことができ、関数から返されます変数に格納できます

ただし、関数を変数に保存する(関数式)だけが関数を作成する方法ではありません。これは関数宣言を使用して行うこともできます。主な違いは次のとおりです。

  1. 関数式には名前を付ける必要がありますが、関数式は匿名にすることができます。
  2. どちらにも、関数を識別するために使用される名前プロパティがあります。関数式の名前プロパティは、それがバインドされている変数の名前ですが、関数宣言の名前は単に与えられた名前です。
  3. 関数宣言は上げられますが、関数式は上げられません。変数のみがundefinedの値を持つように持ち上げられます。

以下に例を示します。

try {
  functionOne();
} catch (e) {
  console.log('i cant run because im not hoisted');
}

functionTwo();

// function expression, does not get hoisted
let functionOne = function randomName() {
    // Some code
};

// function declaration, gets hoisted
function functionTwo() {
   console.log('I get hoisted');
}

try {
  randomName(); // this isn't the proper name, it is functionOne
} catch (e) {
  console.log('You cant call me with randomName my name is function one');
}

0

JSでの表現 :値を返すもの 
例:クロムコンソールで以下を試してください。

a = 10
output : 10

(1 + 3)
output = 4

宣言/文 :値を返さないもの 
例:

if (1 > 2) {
 // do something. 
}

ここで(1> 2)は式ですが、 'if'文はそうではありません。それは何も返さない。 


同様に、関数宣言/ステートメント対関数式があります。 
例を見てみましょう:

// test.js

var a = 10;

// function expression
var fun_expression = function() {
   console.log("Running function Expression");
}

// funciton expression

function fun_declaration() {
   console.log("Running function Statement");
}

重要: JavaScriptエンジンが上記のjsファイルを実行するとどうなりますか。

  • このjsが実行されると、次のことが起こります。

    1. メモリは変数 'a'と 'fun_expression'で作成されます。そして、関数ステートメント 'fun_declaration'用にメモリが作成されます。
    2. 'a'は 'undefined'に割り当てられます。 'fun_expression'は 'undefined'に割り当てられます。 'fun_declaration'は全体としてメモリに保存されます。 
      注:上記のステップ1と2は「実行コンテキスト - 作成フェーズ」と呼ばれます 。 

では、jsをに更新したとします。

// test.js

console.log(a)  //output: udefined (No error)
console.log(fun_expression)  // output: undefined (No error)
console.log(fun_expression()) // output: Error. As we trying to invoke undefined. 
console.log(fun_declaration()) // output: running function statement  (As fun_declaration is already hoisted in the memory). 

var a = 10;

// function expression
var fun_expression = function() {
   console.log('Running function expression')
}

// function declaration

function fun_declaration() {
   console.log('running function declaration')
}

console.log(a)   // output: 10
console.log(fun_expression()) //output: Running function expression
console.log(fun_declaration()) //output: running function declaration

上記のコメントでの出力は、関数式と関数文/宣言の違いを理解するのに役立ちます。

0
Santosh Pillai

注意すべき重要な点は以下のとおりです。 -

二つの機能があるとしましょう: -

sum(1,2);

const sum = function(first, second) {
  return first + second;
}

上記の場合、sumが定義されていないというエラーが出ますが、

sum(1,2);

function sum(first, second) {
  return first + second;
}

この場合function hoistingが行われるので、この関数はエラーにはなりません。

0
Nitesh Ranjan

名前付き関数と無名関数

無名関数式は素早く簡単に入力でき、多くのライブラリやツールはこの慣用的な形式のコードを推奨する傾向があります。ただし、考慮すべきいくつかの 欠点 があります。

  1. 無名関数はスタックトレースに表示するのに有用な名前を持たないため、デバッグがより困難になります。
  2. 名前なしで、関数が再帰などのためにそれ自身を参照する必要がある場合.
  3. 無名関数は名前を省略しているため、コードが読みにくくなる可能性があります。

命名関数式

関数式に名前を付けることは、これらすべての欠点に非常に効果的に対処し、明らかな欠点はありません。ベストプラクティスは、常に関数式に名前を付けることです。

setTimeout(function timeHandler() { // <-- named function here!
  console.log('I've waited 1 second');
}, 1000);

即時呼び出し関数式(IIFE)の命名 

var a = 42;

(function IIFE(global) { // <-- named IIFEs!
  console.log(global.a); // 42
})(window);

注:この場合、関数に名前を付ける、変数に割り当てられた関数の はあまり一般的ではなく、混乱を引き起こす可能性があります。この場合は、arrow関数を使用することをお勧めします。

0
Shakespear

関数を変数として定義するのが好きです。

let first = function(x){
   return x[0];
}

の代わりに:

function first(){
    ....
}

関数を定義するとき、私は式とデコレータを使うことができるからです。例えば:

let safe = function(f){
  try {f()...}
}
let last = safe(function(x){return x[0]}).

ES6では、はるかに短くなりました。

 let last = x => x[0]
 ...........
 function last(x){
     return x[0];
 }
......

let last = safe(x => x[0]);
0
user2693928

両方の関数のもう1つの違いは、functionOneは複数の関数をその中に保持できる変数として使用でき、functionTwoは呼び出されたときにすべて実行されるコードブロックを保持できることです。以下を確認してください。

   var functionOne = (function() {
      return {

         sayHello: function(){
                console.log('say hello')

         },
         redirectPage:function(_url){
                window.location.href = _url;
         }

      }
})();

どの機能を呼び出すかを選択できます。例:functionOne.sayHelloまたはfunctionOne。 redirectPage。また、functionTwoを呼び出すと、コード全体が実行されます。

0
H.Ostwal