無名関数 - javascript 関数 定義




var functionName=function(){}と関数functionName(){} (20)

私は最近他の人のJavaScriptコードを維持管理し始めました。 私はバグを修正したり、機能を追加したり、コードを整理して一貫性を持たせようとしています。

以前の開発者は関数を宣言する2つの方法を使用しています。なぜなら、後ろに理由があるかどうかは分かりません。

2つの方法があります:

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

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


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

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

secondFunction()

Hoisting は、すべての変数宣言および関数宣言を現在のスコープの先頭に移動するJavaScriptインタプリタのアクションです。

しかし、実際の宣言だけが吊り上げられます。 彼らがどこにいるかの割り当てを残すことによって。

  • ページ内で宣言された変数/関数は、そのページ内のどこにでもアクセスできます。
  • 変数/関数内で宣言された関数はローカルスコープを持っています。 関数本体(スコープ)内で使用可能/アクセス可能であることを意味しますが、関数本体の外部では使用できません。

Variable

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';
}
  • ページ内で宣言された関数は、グローバルアクセスを持つページの先頭に持ち上げられます。
  • ファンクションブロック内で宣言されたファンクションは、ブロックの先頭に持ち上げられます。
  • 関数のデフォルト戻り値は ' 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関数を導入しました。矢印関数式は構文が短く、非メソッド関数に最適であり、コンストラクタとして使用することはできません。

ArrowFunction : ArrowParameters => ConciseBodyです。

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

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関数fn(){}


これは関数宣言の2つの可能な方法であり、第2の方法では宣言の前に関数を使用することができます。


それらはいくつかの小さな相違点とかなり似ていますが、最初は無名関数(関数宣言)に割り当てられた変数であり、2つ目はJavaScriptで関数を作成する通常の方法です(無名関数宣言)。どちらも用法、短所:

1.関数式

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

関数式は、関数をより大きな式構文(通常は変数代入)の一部として定義します。式を介して定義された関数式は、名前を付けたり、匿名で表すことができます。関数式は "function"で始まらなければなりません(したがって、以下の自己呼び出しの例のまわりのかっこ)。

変数を関数に代入することはホイストを意味しません.JavaScriptの関数でホイストを呼び出すことができます。宣言する前に呼び出すことができます。変数にアクセスする前に宣言する必要があります。関数が宣言される前に関数にアクセスすることもできますし、関数を書く方法でも、別の関数を返す関数でも、この種の宣言は意味があります。匿名関数の呼び出しにも使用できます。この宣言方法は、JavaScriptでコンストラクタ関数を作成するためのより良い方法です。

2.機能宣言

function functionTwo() {
    // Some code
}

関数宣言は、変数の代入を必要とせずに名前付き関数変数を定義します。関数宣言はスタンドアロンの構造体として発生し、非関数ブロック内にネストすることはできません。Variable Declarationsの兄弟として考えることは役に立ちます。変数宣言は "var"で始まらなければならないのと同様に、関数宣言は "function"で始まらなければなりません。

これはJavaScriptで関数を呼び出す通常の方法です。この関数はJavaScriptのように宣言する前に呼び出すこともできますが、すべての関数がHoistedを取得しますが、 'strict use'がある場合は期待通りにホイストしません。行内で大きくなく、どちらもコンストラクタ関数でない通常の関数をすべて呼び出す。

また、JavaScriptで巻き上げがどのように機能するかについての詳細が必要な場合は、以下のリンクをご覧ください:

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


は、自分自身への内部参照として使用できるように、割り当てられた関数shortcut()に名前を付ける例を示します。John Resig氏は別の例を挙げています - 学習上級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." );

グレッグの答えに対するより良い説明

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();
                            ---------------

グレッグの答えは十分ですが、まだダグラス・クロフォードのビデオを見ているだけで何かを追加したいと思っています。

関数式:

var foo = function foo() {};

関数ステートメント:

function foo() {};

functionステートメントは値varを持つステートメントの省略形functionです。

そう

function foo() {};

に拡大する

var foo = function foo() {};

さらに拡大する

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

そして、彼らは両方ともコードの先頭に吊り下げられています。


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

  • 宣言されている場所から独立しています(ただし、スコープによって制限されています)。
  • 条件付き初期化のような間違いに強い(あなたが望むなら、あなたはまだオーバーライドすることができる)。
  • スコープ機能とは別にローカル関数を割り当てることで、コードがより読みやすくなります。通常、スコープ内で機能が優先され、次にローカル関数が宣言されます。
  • デバッガでは、 "anonymous / evaluated"関数ではなく、コールスタック上に関数名がはっきりと表示されます。

私は、名前付き関数のPROSがさらに続くと考えています。名前付き関数の利点として挙げられているものは、匿名のものには不利です。

歴史的に、匿名関数は、名前付き関数を持つメンバーをリストするための言語としてのJavaScriptの不可能性から生じました。

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

他のコメント作成者は既に上記の2つの亜種の意味の違いをカバーしています。 私は文体の違いに気づきたい:「割り当て」バリエーションだけが別のオブジェクトのプロパティを設定できる。

私はしばしば以下のようなパターンでJavaScriptモジュールをビルドします:

(function(){
    var exports = {};

    function privateUtil() {
            ...
    }

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

    return exports;
})();

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

(また、宣言がそれを禁止する間、代入はステートメントの後にセミコロンを必要とすることに注意してください)。


他の誰もが吊るした部分を徹底的に覆ったからといって、自分の答えを加えています。

私は長い間今のところどちらの方法が良いか不思議に思っています。http://jsperf.comに感謝します。

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


以下に挙げる2つの異なる宣言の間には、3つの注目すべき比較があります。

  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=いきません(superseedsので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(){}場合、関数 .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つの異なる型を格納するなど、多型を排除しようとすると、もっと価値があるかもしれません。

「最近のブロック」とは何ですか?

「最も近いブロック」は、最も近い「関数」(非同期関数、ジェネレータ関数、および非同期ジェネレータ関数を含む)です。しかしながら、興味深いことに、a 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/ catch/ finallyswitchdo/ whilewith

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;
    }
})();


最初に私はGregを修正したい: function abc(){}もスコープされています - 名前abcはこの定義が遭遇したスコープで定義されています。 例:

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

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

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つは、関数オブジェクトの "名前"属性です( Internet Explorerではサポートされていません )。 基本的に、次のような関数を定義すると

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

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

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

その名前は空です - 私たちは無名関数を作成し、変数に代入しました。

組み合わされたスタイルを使用する別の理由は、短い内部名を使用して自分自身を参照し、外部ユーザーに長い間競合しない名前を付けることです。

// 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を使用する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定義していないことをabcとして、グローバルに定義したことを知っています。 このスタイルの定義は、 eval()内部で使用されても弾力的です。 定義の間

function abc(){};

コンテキストに依存し、特にeval()場合には、実際にどこに定義されているかを推測することができます。答えは:ブラウザによって異なります。


最初のもの(関数doSomething(x))はオブジェクト記法の一部でなければなりません。

2番目のvar doSomething = function(x){ alert(x);}関数()は単純に無名関数を作成し、それを変数に代入しますdoSomething。だからdoSomething()は関数を呼び出します。

関数宣言関数式が何であるか知りたいかもしれません。

関数宣言は、変数の代入を必要とせずに、名前付き関数変数を定義します。関数宣言はスタンドアロンのコンストラクトとして実行され、非関数ブロック内にネストすることはできません。

function foo() {
    return 3;
}

ECMA 5(13.0)は、構文を
関数として定義します。Identifier(FormalParameterList opt){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(FormalParameterList opt){FunctionBody}


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

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を強くお勧めしますlink


現時点の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:
[email protected]://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


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


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


func.name: 
Trace:
[email protected]://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


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


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


func.name: 
Trace:
[email protected]://localhost:8000/test.js:17:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


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


func.name: l
Trace:
[email protected]://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:
[email protected]://localhost:8000/test.js:33:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: p
Trace:
[email protected]://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:
[email protected]://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

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

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

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

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

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

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

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

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

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

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

func.name: p
Trace:
[email protected]://localhost:8000/test.js:38:30
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

私は非常に具体的な理由で上記の抽象的な方法で理論がカバーされていますが、JavaScriptの専門知識が限られている私のような人を助けるかもしれません。

私は160個の独立したデザインのブランドで走るために必要なコードを持っています。コードのほとんどは共有ファイルにありますが、ブランド固有のものはブランドごとに別々のファイルにあります。

いくつかのブランディングは特定の機能を必要とし、一部のものはそうではありません。時々、新しいブランディング特有のことをするための新しい機能を追加する必要があります。私は共有コードを変更してうれしく思いますが、ブランディングファイルを160セットすべて変更する必要はありません。

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

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

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


違いは、 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(); }
}

実際には、 use strictが有効でない限り、 testの値にかかわらずfunctionThree定義します。この場合、単にエラーが発生します。


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

条項:

クイックリスト:

  • 関数宣言

  • "匿名" function(この用語にもかかわらず、名前を持つ関数を作成することがあります)

  • 名前付きfunction

  • アクセサファンクションイニシャライザ(ES5 +)

  • Arrow Function Expression(ES2015 +) (匿名関数式のように、明示的な名前はなく、名前付きの関数を作成できます)

  • オブジェクトイニシャライザでのメソッド宣言(ES2015 +)

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

関数宣言

最初の形式は次のような関数宣言です:

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

関数宣言は宣言です。 それは文や表現ではありません。 そういうわけで、あなたはそれを続けません; (そうしても無害ですが)。

関数宣言は、ステップバイステップのコードが実行されるに、実行がコンテキストが入るコンテキストに入ると処理されます。 作成する関数には適切な名前(上記の例では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
}

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

これを行うことはES2015までは規定されていませんでしたが、ブロック内の関数宣言をサポートすることは許容された拡張でした。 残念なことに(と必然的に)、異なるエンジンは違ったことをしました。

ES2015以降、仕様には何をすべきかが記載されています。 実際、それは3つの別々のことを行います:

  1. Webブラウザではない緩やかなモードで 、JavaScriptエンジンは1つのことを行うことになっています
  2. Webブラウザ上の緩いモードでは、JavaScriptエンジンは何か他のことをするはずです
  3. 厳密なモード(ブラウザかどうか)では、JavaScriptエンジンはまだ別のことをやっているはずです

ルーズモードのルールは難しいですが、 厳密なモードでは、ブロック内の関数宣言は簡単です。ブロックにローカルであり( ブロックスコープがあり、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については、仕様の中のSetFunctionNameを検索してSetFunctionName - それは場所全体に現れます)。

名前付きfunction

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

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

これが作成する関数は、適切な名前(この場合はw )を持ちます。 すべての式と同様に、これはコードの段階的実行で到達したときに評価されます。 関数の名前は、式が現れるスコープに追加されません 。 名前関数自体の範囲内にあります:

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 +)

機能がほとんど気づかれずに回り込むことがあります。 それはアクセサー関数の場合です。 ここに例があります:

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"

私がこの関数を使用したとき、私は()を使わなかったことに注意してください! それはプロパティのアクセサー関数だからです。 プロパティを取得して通常の方法で設定しますが、その場では関数が呼び出されます。

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

矢印機能式(ES2015 +)

ES2015は矢印機能を持っています 。 ここに1つの例があります:

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

map()コールにn => n * 2ものが隠れているのを見てください。 それは関数です。

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

  1. 彼らはこれを持っていません。 代わりに、彼らは定義されているコンテキストのthis閉じます。 (彼らはargumentsを終わらせ、関連する場合はsuper閉じarguments 。)これは彼らの中の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));

{ ... }ないバージョンは、 式本体または簡潔な本体を持つ矢印関数と呼ばれます。 (また、 簡潔な矢印関数です。)ボディを定義する{ ... }持つものは、 関数本体を持つ矢印関数です。 (また: 冗長な矢印機能。)

オブジェクトイニシャライザでのメソッド宣言(ES2015 +)

ES2015では、関数を参照するプロパティを宣言する短い形式を使用できます。 次のようになります。

var o = {
    foo() {
    }
};

ES5以前では、次のようになります。

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

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つはgetFullNameに割り当てられた関数であるPerson.prototypeです。


コンピュータ科学の用語では、無名関数と名前付き関数について説明します。私は最も重要な違いは、匿名関数は名前に縛られていないということです。したがって、名前は無名関数です。JavaScriptでは、実行時に動的に宣言されるファーストクラスのオブジェクトです。

匿名関数とラムダ計算の詳細については、Wikipediaが良いスタートです(http://en.wikipedia.org/wiki/Anonymous_function)。





idioms