web-dev-qa-db-fra.com

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

J'ai récemment commencé à maintenir le code JavaScript de quelqu'un d'autre. Je corrige des bugs, j'ajoute des fonctionnalités et j'essaie également de nettoyer le code et de le rendre plus cohérent.

Le développeur précédent utilise deux manières de déclarer des fonctions et je ne peux pas déterminer s’il ya une raison derrière cela ou non.

Les deux manières sont:

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

Quelles sont les raisons d'utiliser ces deux méthodes différentes et quels sont les avantages et les inconvénients de chacune? Y a-t-il quelque chose qui peut être fait avec une méthode qui ne peut pas être fait avec l'autre?

6315
Richard Garside

La différence est que functionOne est une expression de fonction et n'est donc définie que lorsque cette ligne est atteinte, alors que functionTwo est une déclaration de fonction et est définie dès que sa fonction ou son script est exécuté (en raison de hoisting ). 

Par exemple, une expression de fonction:

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

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

Et une déclaration de fonction: 

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

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

Cela signifie également que vous ne pouvez pas définir de manière conditionnelle des fonctions à l'aide de déclarations de fonctions:

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

Ce qui précède définit en fait functionThree quelle que soit la valeur de test - sauf si use strict est en vigueur, auquel cas cela déclenche simplement une erreur.

4694
Greg

Je veux d’abord corriger Greg: function abc(){} a également une portée - le nom abc est défini dans la portée où cette définition est rencontrée. Exemple:

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

Deuxièmement, il est possible de combiner les deux styles:

var xyz = function abc(){};

xyz va être défini comme d'habitude, abc n'est pas défini dans tous les navigateurs sauf Internet Explorer - ne vous fiez pas à sa définition. Mais il sera défini à l'intérieur de son corps:

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

Si vous souhaitez aliaser des fonctions sur tous les navigateurs, utilisez ce type de déclaration:

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

Dans ce cas, xyz et abc sont des alias du même objet:

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

L'attribut "name" des objets fonction ( non pris en charge par Internet Explorer ) constitue une raison impérieuse d'utiliser le style combiné. Fondamentalement, lorsque vous définissez une fonction comme

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

son nom est automatiquement attribué. Mais quand vous le définissez comme

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

son nom est vide - nous avons créé une fonction anonyme et l'avons affectée à une variable.

Une autre bonne raison d'utiliser le style combiné consiste à utiliser un nom interne court pour faire référence à lui-même, tout en fournissant un nom long et non conflictuel aux utilisateurs externes:

// 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);
  // ...
}

Dans l'exemple ci-dessus, nous pouvons faire la même chose avec un nom externe, mais ce sera trop lourd (et plus lent).

(Une autre façon de se référer à lui-même consiste à utiliser arguments.callee, qui est encore relativement long et qui n'est pas pris en charge en mode strict.)

Au fond, JavaScript traite les deux instructions différemment. C'est une déclaration de fonction:

function abc(){}

abc est défini partout dans la portée actuelle:

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

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

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

En outre, il est passé par une déclaration return:

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

Ceci est une expression de fonction:

var xyz = function(){};

xyz est défini à partir du point d’affectation:

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

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

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

Déclaration de fonction contre expression de fonction est la vraie raison pour laquelle Greg a démontré une différence.

Fait amusant:

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

Personnellement, je préfère la déclaration "expression de fonction" car je peux ainsi contrôler la visibilité. Quand je définis la fonction comme

var abc = function(){};

Je sais que j'ai défini la fonction localement. Quand je définis la fonction comme

abc = function(){};

Je sais que je l'ai défini globalement à condition de ne définir abc nulle part dans la chaîne d'étendues. Ce style de définition est résilient même lorsqu'il est utilisé dans eval(). Alors que la définition

function abc(){};

dépend du contexte et peut vous laisser deviner où il est réellement défini, en particulier dans le cas de eval() - la réponse est: Cela dépend du navigateur.

1853
Eugene Lazutkin

Voici le récapitulatif des formulaires standard qui créent des fonctions: (Initialement écrit pour une autre question, mais adapté après avoir été déplacé dans la question canonique.)

Termes:

La liste rapide:

  • Déclaration de fonction

  • "Anonymous" function Expression (qui malgré le terme crée parfois des fonctions avec des noms)

  • Nommé function Expression

  • Initialiseur de fonction d'accesseur (ES5 +)

  • Expression de fonction de flèche (ES2015 +) (qui, comme les expressions de fonction anonymes, ne comporte pas de nom explicite, et peut néanmoins créer des fonctions avec des noms)

  • Déclaration de méthode dans Object Initializer (ES2015 +)

  • Déclarations de constructeur et de méthode dans class (ES2015 +)

Déclaration de fonction

La première forme est une déclaration de fonction, qui ressemble à ceci:

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

Une déclaration de fonction est une déclaration; ce n'est pas une déclaration ou une expression. En tant que tel, vous ne le suivez pas avec un ; (bien que ce soit inoffensif).

Une déclaration de fonction est traitée lorsque l'exécution entre dans le contexte dans lequel elle apparaît avant que aucun code étape par étape ne soit exécuté. La fonction qu'il crée reçoit un nom propre (x dans l'exemple ci-dessus) et ce nom est placé dans la portée dans laquelle la déclaration apparaît.

Comme il est traité avant tout code étape par étape dans le même contexte, vous pouvez procéder comme suit:

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

Jusqu'au ES2015, les spécifications ne couvraient pas ce qu'un moteur JavaScript devrait faire si vous insérez une déclaration de fonction dans une structure de contrôle telle que try, if, switch, while, etc., comme ceci:

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

Et comme ils sont traités avant ​​le code étape par étape est exécuté, il est difficile de savoir quoi faire si ils se trouvent dans une structure de contrôle.

Bien que cela n'ait pas été spécifié avant ES2015, il s'agissait d'un extension autorisée pour prendre en charge les déclarations de fonction dans des blocs. Malheureusement (et inévitablement), différents moteurs ont fait des choses différentes.

À compter de ES2015, la spécification indique quoi faire. En fait, cela donne trois choses distinctes à faire:

  1. Si en mode lâche not ​​sur un navigateur Web, le moteur JavaScript est censé faire une chose
  2. Si le navigateur Web est en mode lâche, le moteur JavaScript est censé faire autre chose.
  3. Si en mode strict ​​(navigateur ou non), le moteur JavaScript est supposé faire encore autre chose

Les règles pour les modes lâches sont délicates, mais en mode strict, les déclarations de fonctions en blocs sont simples: elles sont locales au bloc (elles ont portée du bloc, ce qui est également nouveau dans ES2015), et ils sont hissés au sommet du bloc. Alors:

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

"Anonymous" function Expression

La deuxième forme commune s'appelle un expression de fonction anonyme:

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

Comme toutes les expressions, elle est évaluée lorsqu'elle est atteinte lors de l'exécution pas à pas du code.

Dans ES5, la fonction créée n'a pas de nom (c'est anonyme). Dans ES2015, un nom est attribué à la fonction si possible en l'inférant du contexte. Dans l'exemple ci-dessus, le nom serait y. Quelque chose de similaire est fait lorsque la fonction est la valeur d'un initialiseur de propriété. (Pour plus de détails sur le moment où cela se produit et les règles, recherchez SetFunctionName dans la spécification - il apparaît partout ​​l'endroit.)

Nommé function Expression

La troisième forme est un expression de fonction nommée ("NFE"):

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

La fonction créée a un nom propre (w dans ce cas). Comme toutes les expressions, ceci est évalué lorsqu'il est atteint dans l'exécution pas à pas du code. Le nom de la fonction est not ​​ajouté à la portée dans laquelle l'expression apparaît; le nom est ​​dans la fonction elle-même:

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

Notez que les ENF ont souvent été une source de bogues pour les implémentations de JavaScript. IE8 et versions antérieures, par exemple, gèrent les NFE complètement incorrectement , créant deux fonctions différentes à deux moments différents. Les premières versions de Safari avaient également des problèmes. La bonne nouvelle est que les versions actuelles des navigateurs (IE9 et les versions supérieures, Safari actuelle) ne rencontrent plus ces problèmes. (Malheureusement, IE8 n’a toujours pas été utilisé à ce jour, et l’utilisation des NFE avec un code pour le Web en général est toujours problématique.)

Initialiseur de fonction d'accesseur (ES5 +)

Parfois, les fonctions peuvent se glisser en grande partie inaperçues; c'est le cas avec fonctions d'accès. Voici un exemple:

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"

Notez que lorsque j'ai utilisé la fonction, je n'utilisais pas ()! C'est parce que c'est une fonction d'accesseur pour une propriété. Nous obtenons et définissons la propriété de manière normale, mais dans les coulisses, la fonction est appelée.

Vous pouvez également créer des fonctions d'accesseur avec Object.defineProperty, Object.defineProperties et le deuxième argument moins connu de Object.create.

Expression de fonction de flèche (ES2015 +)

ES2015 nous apporte la fonction de la flèche. Voici un exemple:

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

Voir que n => n * 2 chose cachée dans l'appel map()? C'est une fonction.

Quelques éléments concernant les fonctions de flèche:

  1. Ils n'ont pas leur propre this. Au lieu de cela, ils fermer la this du contexte où ils sont définis. (Ils se ferment également sur arguments et, le cas échéant, super.) Cela signifie que la this qu’ils contiennent est identique à la this où ils sont créés, et ne peut pas être changé.

  2. Comme vous l'avez remarqué avec ce qui précède, vous n'utilisez pas le mot clé function; à la place, vous utilisez =>.

L'exemple n => n * 2 ci-dessus en est une forme. Si vous avez plusieurs arguments pour passer la fonction, vous utilisez des parens:

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

(Rappelez-vous que Array#map passe l’entrée en tant que premier argument et l’index en tant que second.)

Dans les deux cas, le corps de la fonction n'est qu'une expression; la valeur de retour de la fonction sera automatiquement le résultat de cette expression (vous n'utilisez pas un return explicite).

Si vous faites plus qu'une seule expression, utilisez {} et un return explicite (si vous devez renvoyer une valeur), comme d'habitude:

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

La version sans { ... } s'appelle une fonction de flèche avec un corps d'expression ou corps concis. (Également: une fonction de flèche concise.) Celle avec { ... } définissant le corps est une fonction de flèche avec un corps de la fonction. (Également: une fonction de flèche verbose.)

Déclaration de méthode dans Object Initializer (ES2015 +)

ES2015 autorise une forme plus courte de déclaration d'une propriété faisant référence à une fonction appelée définition de méthode; ça ressemble à ça:

var o = {
    foo() {
    }
};

l'équivalent presque équivalent dans ES5 et antérieur serait:

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

la différence (autre que la verbosité) est qu'une méthode peut utiliser super, mais pas une fonction. Ainsi, par exemple, si vous aviez un objet qui définissait (par exemple) valueOf en utilisant la syntaxe de la méthode, il pourrait utiliser super.valueOf() pour obtenir la valeur que Object.prototype.valueOf aurait renvoyé (avant de faire autre chose avec il), alors que la version ES5 devrait faire Object.prototype.valueOf.call(this) à la place.

Cela signifie également que la méthode a une référence à l’objet sur lequel elle a été définie. Ainsi, si cet objet est temporaire (par exemple, vous le transmettez à Object.assign en tant qu’un des objets source), syntaxe de la méthode - pourrait ​​signifie que l'objet est conservé en mémoire alors qu'il aurait pu être récupéré (si le moteur JavaScript ne détecte pas cette situation et ne le gère pas si aucune des méthodes n'utilise super).

Déclarations de constructeur et de méthode dans class (ES2015 +)

ES2015 nous apporte la syntaxe class, y compris les constructeurs déclarés et les méthodes:

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

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

Il y a deux déclarations de fonction ci-dessus: une pour le constructeur, qui porte le nom Person, et l'autre pour getFullName, fonction attribuée à Person.prototype.

599
T.J. Crowder

Parlant du contexte global, l’instruction var et une FunctionDeclaration à la fin créeront une propriété non supprimable sur l’objet global, mais la valeur de peut être écrasée.

La différence subtile entre les deux méthodes est que lorsque le processus Instance de variable est exécuté (avant l'exécution de code proprement dite), tous les identificateurs déclarés avec var seront initialisés avec undefined et que ceux utilisés par FunctionDeclaration seront disponibles , par exemple:

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

L'affectation de barFunctionExpression a lieu jusqu'au moment de l'exécution.

Une propriété globale créée par une FunctionDeclaration peut être écrasée sans problème, tout comme une valeur de variable, par exemple:

 function test () {}
 test = null;

Une autre différence évidente entre vos deux exemples est que la première fonction n’a pas de nom, mais que la seconde l’a, ce qui peut être très utile lors du débogage (c’est-à-dire l’inspection d’une pile d’appels).

À propos de votre premier exemple modifié (foo = function() { alert('hello!'); };), il s’agit d’une tâche non déclarée. Je vous encourage vivement à toujours utiliser le mot clé var.

Avec une affectation, sans l'instruction var, si l'identificateur référencé n'est pas trouvé dans la chaîne d'étendue, il deviendra une propriété supprimable de l'objet global.

De plus, les assignations non déclarées jettent une ReferenceError dans ECMAScript 5 sous Strict Mode .

À lire absolument:

Note: Cette réponse a été fusionnée à partir de une autre question , dans laquelle le doute majeur et la fausse idée du PO étaient que les identifiants déclarés avec un FunctionDeclaration, ne pouvaient pas être remplacés, ce qui n'est pas le cas.

138
CMS

Les deux extraits de code que vous avez publiés là-bas se comporteront pratiquement de la même manière.

Cependant, la différence de comportement réside dans le fait qu'avec la première variante (var functionOne = function() {}), cette fonction ne peut être appelée qu'après ce point dans le code.

Avec la deuxième variante (function functionTwo()), la fonction est disponible pour le code qui s'exécute ci-dessus où la fonction est déclarée.

En effet, avec la première variante, la fonction est affectée à la variable foo au moment de l'exécution. Dans le second cas, la fonction est affectée à cet identifiant, foo, au moment de l'analyse.

_ {Plus d'informations techniques} _

JavaScript a trois façons de définir des fonctions.

  1. Votre premier extrait montre un expression de fonction. Cela implique l'utilisation de l'opérateur "function" pour créer une fonction - le résultat de cet opérateur peut être stocké dans n'importe quelle propriété de variable ou d'objet. L'expression de fonction est puissante de cette façon. L’expression de fonction est souvent appelée "fonction anonyme", car elle n’a pas besoin de nom,
  2. Votre deuxième exemple est une déclaration de fonction. Ceci utilise l'instruction "function" pour créer une fonction. La fonction est disponible au moment de l'analyse et peut être appelée n'importe où dans cette étendue. Vous pouvez toujours le stocker ultérieurement dans une propriété de variable ou d'objet.
  3. La troisième manière de définir une fonction est le constructeur "Function ()"}, qui n'est pas présenté dans votre message d'origine. Il n'est pas recommandé de l'utiliser car cela fonctionne de la même manière que eval(), ce qui pose des problèmes.
116
thomasrutter

Une meilleure explication à réponse de Greg

functionTwo();
function functionTwo() {
}

Pourquoi pas d'erreur? On nous a toujours appris que les expressions sont exécutées de haut en bas (??)

Parce que:

Les déclarations de fonction et les déclarations de variable sont toujours déplacées (hoisted) de manière invisible en haut de la portée qu'elles contiennent par l'interpréteur JavaScript. Les paramètres de fonction et les noms définis par la langue sont, évidemment, déjà là. ben cherry

Cela signifie que le code ressemble à ceci:

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

Notez que la partie cession des déclarations n’a pas été levée. Seul le nom est hissé.

Mais dans le cas des déclarations de fonction, tout le corps de la fonction sera également levé}:

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

D'autres commentateurs ont déjà couvert la différence sémantique des deux variantes ci-dessus. Je voulais noter une différence stylistique: seule la variante "affectation" peut définir une propriété d'un autre objet.

Je construis souvent des modules JavaScript avec un motif comme celui-ci:

(function(){
    var exports = {};

    function privateUtil() {
            ...
    }

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

    return exports;
})();

Avec ce modèle, vos fonctions publiques utiliseront toutes une affectation, alors que vos fonctions privées utiliseront une déclaration.

(Notez également que l'affectation doit nécessiter un point-virgule après la déclaration, alors que la déclaration l'interdit.)

88
Sean McMillan

Une illustration du moment où préférer la première méthode à la seconde consiste à éviter de remplacer les définitions précédentes d'une fonction.

Avec

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

, cette définition de myfunction remplacera toute définition précédente, car elle sera effectuée au moment de l’analyse.

Tandis que

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

définit correctement la variable myfunction uniquement lorsque condition est rempli.

74
Mbengue Assane

Une raison importante est d'ajouter une et une seule variable comme "racine" de votre espace de noms ...

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

}

ou

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

Il existe de nombreuses techniques pour l'espacement de noms. C'est devenu plus important avec la pléthore de modules JavaScript disponibles.

Voir aussi Comment déclarer un espace de noms en JavaScript?

60
Rob

Hoisting _ ​​l’action de l’interprète JavaScript consistant à déplacer toutes les déclarations de variable et de fonction en haut de la portée actuelle. 

Cependant, seules les déclarations effectives sont levées. En laissant les assignations où elles sont.

  • les variables/fonctions déclarées à l'intérieur de la page sont globales et accessibles n'importe où dans cette page.
  • la variable/Les fonctions déclarées à l'intérieur de la fonction ont une portée locale. signifie qu'ils sont disponibles/accessibles dans le corps de la fonction (scope), ils ne sont pas disponibles en dehors du corps de la fonction.

Variable

Javascript est appelé langage faiblement typé. Ce qui signifie que les variables Javascript peuvent contenir une valeur quelconque de Data-Type . Javascript prend automatiquement en charge de changer le type de variable en fonction de la valeur/du littéral fourni lors de l'exécution.

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.
};  

Une fonction

function Identifier_opt ( FormalParameterList_opt ) { 
      FunctionBody | sequence of statements

      « return;  Default undefined
      « return 'some data';
}
  • les fonctions déclarées à l'intérieur de la page sont hissées en haut de la page avec un accès global.
  • les fonctions déclarées à l'intérieur du bloc fonctionnel sont hissées en haut du bloc.
  • La valeur par défaut de la fonction est ' undefined ', Variable déclaration, la valeur par défaut est également 'undefined'

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

Déclaration de fonction

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

Fonction Expression

        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'
    };

Fonction assignée à la variable Exemple:

(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 interprété comme

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

Vous pouvez vérifier la déclaration de fonction et le test d’expression sur différents navigateurs en utilisant jsperf Test Runner


Classes de fonction du constructeur ES5 : objets de fonction créés à l'aide de Function.prototype.bind

JavaScript traite les fonctions comme des objets de première classe. Par conséquent, en tant qu'objet, vous pouvez affecter des propriétés à une fonction.

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 introduit Fonction de flèche: une expression de fonction de flèche a une syntaxe plus courte, elle convient mieux aux fonctions autres que de méthode et ne peut pas être utilisée en tant que constructeur.

ArrowFunction : ArrowParameters => ConciseBody .

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

J'ajoute ma propre réponse simplement parce que tout le monde a couvert la partie de levage de manière approfondie.

Cela fait longtemps que je me demande quelle est la meilleure solution. Grâce à http://jsperf.com maintenant, je sais :)

enter image description here

Les déclarations de fonctions sont plus rapides et c'est ce qui compte vraiment dans Web Dev, n'est-ce pas? ;)

36
Leon Gaban

Une déclaration de fonction et une expression de fonction affectée à une variable se comportent de la même manière une fois la liaison établie.

Il y a cependant une différence entre comment et lorsque l'objet de fonction est réellement associé à sa variable. Cette différence est due au mécanisme appelé variable hoisting en JavaScript.

Fondamentalement, toutes les déclarations de fonction et les déclarations de variable sont placées en haut du function dans lequel la déclaration se produit (c’est pourquoi nous disons que JavaScript a la portée function).

  • Quand une déclaration de fonction est levée, le corps de la fonction "suit" Ainsi, lorsque le corps de la fonction est évalué, la variable sera immédiatementbe liée à un objet de fonction.

  • Lorsqu'une déclaration de variable est levée, l'initialisation ne suit pas , Mais elle est "laissée derrière". La variable est initialisée à undefined au début du corps de la fonction et sera assignée Une valeur à son emplacement d'origine dans le code. (En fait, une valeur sera attribuée à à chaque emplacement où se produit une déclaration d'une variable portant le même nom.)

L'ordre de levage est également important: les déclarations de fonction ont priorité sur les déclarations de variable portant le même nom, et la dernière déclaration de fonction a priorité sur les déclarations de fonction précédentes portant le même nom.

Quelques exemples...

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

La variable foo est hissée en haut de la fonction, initialisée à undefined, de sorte que !foo est true, de sorte que foo est attribué à 10. La variable foo en dehors de bar ne joue aucun rôle et est intacte. 

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

Les déclarations de fonction ont priorité sur les déclarations de variable et la dernière déclaration de fonction "sticks".

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

Dans cet exemple, a est initialisé avec l'objet fonction résultant de l'évaluation de la deuxième déclaration de fonction, puis est attribué à 4.

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

Ici, la déclaration de fonction est levée en premier, en déclarant et en initialisant la variable a. Ensuite, cette variable est assignée 10. En d'autres termes: l'affectation n'affecte pas la variable externe a.

32
eljenso

Le premier exemple est une déclaration de fonction:

function abc(){}

Le deuxième exemple est une expression de fonction:

var abc = function() {};

La principale différence réside dans la manière dont ils sont hissés (levés et déclarés). Dans le premier exemple, la déclaration de fonction entière est levée. Dans le deuxième exemple, seule la variable 'abc' est levée, sa valeur (la fonction) sera indéfinie et la fonction elle-même reste à la position dans laquelle elle a été déclarée.

Pour le dire simplement:

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

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

Pour en savoir plus sur ce sujet, je vous le recommande vivement link

30
sla55er

En termes de coût de maintenance du code, les fonctions nommées sont plus préférables:

  • Indépendants du lieu où ils sont déclarés (mais toujours limités par leur portée).
  • Plus résistant aux erreurs telles que l'initialisation conditionnelle (vous pouvez toujours remplacer si vous le souhaitez).
  • Le code devient plus lisible en attribuant des fonctions locales séparément de la fonctionnalité de la portée. Habituellement, dans le champ d'application, la fonctionnalité commence en premier, suivie par les déclarations de fonctions locales.
  • Dans un débogueur, vous verrez clairement le nom de la fonction sur la pile d'appels au lieu d'une fonction "anonyme/évaluée".

Je soupçonne que plus de PROS pour les fonctions nommées sont suivis. Et ce qui est répertorié comme un avantage des fonctions nommées est un inconvénient pour les fonctions anonymes.

Historiquement, les fonctions anonymes résultaient de l'incapacité de JavaScript à utiliser un langage pour répertorier les membres avec des fonctions nommées:

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

J'utilise l'approche variable dans mon code pour une raison très spécifique, dont la théorie a été abordée de manière abstraite ci-dessus, mais un exemple pourrait aider certaines personnes comme moi, avec une expertise limitée de JavaScript.

J'ai le code que je dois exécuter avec 160 marques conçues de manière indépendante. La plupart du code se trouve dans des fichiers partagés, mais les éléments spécifiques à la marque se trouvent dans un fichier séparé, un pour chaque marque.

Certaines marques nécessitent des fonctions spécifiques, d'autres non. Parfois, je dois ajouter de nouvelles fonctions pour faire de nouvelles choses spécifiques à la marque. Je suis heureux de changer le code partagé, mais je ne veux pas avoir à changer les 160 ensembles de fichiers de marque.

En utilisant la syntaxe de variable, je peux déclarer la variable (un pointeur de fonction essentiellement) dans le code partagé et assigner une fonction de stub triviale ou la définir sur null.

Les marques qui nécessitent une implémentation spécifique de la fonction peuvent ensuite définir leur version de la fonction et l’affecter à la variable si elles le souhaitent, les autres ne faisant rien. Je peux tester une fonction null avant de l'exécuter dans le code partagé.

D'après les commentaires des personnes ci-dessus, il est peut-être possible de redéfinir une fonction statique également, mais je pense que la solution variable est belle et claire.

24
Herc

En termes d’informatique, on parle de fonctions anonymes et de fonctions nommées. Je pense que la différence la plus importante est qu’une fonction anonyme n’est pas liée à un nom, d’où le nom de fonction anonyme. En JavaScript, il s'agit d'un objet de première classe déclaré dynamiquement au moment de l'exécution.

Pour plus d'informations sur les fonctions anonymes et le calcul lambda, Wikipedia est un bon début ( http://en.wikipedia.org/wiki/Anonymous_function ).

22
Kafka

_ { Greg's Answer } _ est suffisant, mais j'aimerais quand même ajouter quelque chose que j'ai appris tout à l'heure en regardant Douglas Crockford des vidéos.

Expression de fonction:

var foo = function foo() {};

Instruction de fonction:

function foo() {};

L'instruction de fonction est simplement un raccourci pour l'instruction var avec une valeur function.

Alors

function foo() {};

s'étend à

var foo = function foo() {};

Qui s'étend plus loin à:

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

Et ils sont tous deux hissés au sommet du code.

Screenshot from video

22
Rohan

@EugeneLazutkin donne un exemple dans lequel il nomme une fonction attribuée pour pouvoir utiliser shortcut() comme référence interne à elle-même. John Resig donne un autre exemple - en copiant une fonction récursive affectée à un autre objet dans son Learning Advanced Javascript tutorial. Bien que l’attribution de fonctions à des propriétés ne soit pas une question essentielle ici, je vous recommande d’essayer activement le didacticiel - exécutez le code en cliquant sur le bouton situé dans le coin supérieur droit, puis double-cliquez sur le code à modifier selon vos préférences.

Exemples du didacticiel: appels récursifs dans yell():

Les tests échouent lorsque l'objet ninja d'origine est supprimé. (page 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?" ); 
}

Si vous nommez la fonction qui sera appelée de manière récursive, les tests réussiront. (page 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

Une autre différence qui n’est pas mentionnée dans les autres réponses est que si vous utilisez la fonction anonyme

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

et l'utiliser comme un constructeur comme dans

var one = new functionOne();

alors one.constructor.name ne sera pas défini. Function.name n'est pas standard mais est supporté par Firefox, Chrome, d'autres navigateurs dérivés de Webkit et IE 9+.

Avec 

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

il est possible de récupérer le nom du constructeur sous forme de chaîne avec two.constructor.name.

16
Ingo Kegel

Le premier (fonction doQuelquechose (x)) devrait faire partie d'une notation d'objet.

La seconde (var doSomething = function(x){ alert(x);}) crée simplement une fonction anonyme et l’assigne à une variable, doSomething. Alors, quelque chose () appellera la fonction.

Vous voudrez peut-être savoir ce qu'est une déclaration de fonction et expression de fonction.

Une déclaration de fonction définit une variable de fonction nommée sans nécessiter d'affectation de variable. Les déclarations de fonctions sont des constructions autonomes et ne peuvent pas être imbriquées dans des blocs non fonctionnels.

function foo() {
    return 3;
}

ECMA 5 (13.0) définit la syntaxe comme suit: 
identifiant de fonction (FormalParameterListopt ) {FunctionBody}

Dans la condition ci-dessus, le nom de la fonction est visible dans son étendue et dans l'étendue de son parent (sinon, il serait inaccessible).

Et dans une expression de fonction

Une expression de fonction définit une fonction dans le cadre d'une syntaxe d'expression plus grande (généralement une affectation de variable). Les fonctions définies via des expressions de fonctions peuvent être nommées ou anonymes. Les expressions de fonction ne doivent pas commencer par «fonction».

// 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) définit la syntaxe comme suit: 
identifiant de fonctionopt (FormalParameterListopt ) {FunctionBody}

14
NullPoiиteя

Si vous utilisiez ces fonctions pour créer des objets, vous obtiendriez:

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

J'énumère les différences ci-dessous:

  1. Une déclaration de fonction peut être placée n'importe où dans le code. Même s'il est appelé avant que la définition n'apparaisse dans le code, il est exécuté lorsque la déclaration de fonction est validée en mémoire ou levée avant qu'un autre code de la page ne commence à être exécuté.

    Regardez la fonction ci-dessous:

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

    En effet, pendant l'exécution, cela ressemble à: -

    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
    

    Une expression de fonction, si elle n’est pas définie avant de l’appeler, entraînera une erreur. De même, la définition de la fonction elle-même n'est pas déplacée en haut ni engagée en mémoire comme dans les déclarations de fonction. Mais la variable à laquelle nous attribuons la fonction est levée et undefined lui est assignée.

    Même fonction en utilisant des expressions de fonction:

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

    En effet, pendant l'exécution, cela ressemble à:

    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. Il est dangereux d’écrire des déclarations de fonction dans des blocs non fonctionnels comme if car elles ne seront pas accessibles.

    if (test) {
        function x() { doSomething(); }
    }
    
  3. L'expression de fonction nommée comme celle ci-dessous peut ne pas fonctionner dans les navigateurs Internet Explorer antérieurs à la version 9.

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

À la lumière de l'argument "les fonctions nommées apparaissent dans les traces de pile", les moteurs JavaScript modernes sont en fait tout à fait capables de représenter des fonctions anonymes.

A ce jour, V8, SpiderMonkey, Chakra et Nitro font toujours référence aux fonctions nommées par leurs noms. Ils font presque toujours référence à une fonction anonyme par son identifiant s'il en a un.

SpiderMonkey peut déterminer le nom d'une fonction anonyme renvoyée par une autre fonction. Le reste ne peut pas.

Si vous vouliez vraiment, vraiment, que vos rappels d'itérateur et de succès apparaissent dans la trace, vous pouvez les nommer aussi ...

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

Mais dans la plupart des cas, il ne vaut pas la peine de souligner.

Harnais ( 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

SpiderMonkey

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

Chakra

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)

Nitro

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

En JavaScript, il existe deux manières de créer des fonctions:

  1. Déclaration de fonction:

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

    Ceci est très basique, explicite, utilisé dans de nombreuses langues et standard dans la famille de langues C. Nous avons déclaré une fonction définie et exécuté en l'appelant.

    Ce que vous devriez savoir, c’est que les fonctions sont en réalité des objets en JavaScript; en interne, nous avons créé un objet pour la fonction ci-dessus et lui avons attribué un nom appelé fn ou la référence à l'objet est stockée dans fn. Les fonctions sont des objets en JavaScript; une instance de fonction est en réalité une instance d'objet.

  2. Expression de la fonction:

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

    JavaScript a des fonctions de première classe, c’est-à-dire créer une fonction et l’affecter à une variable comme vous créez une chaîne ou un nombre et l’affectez à une variable. Ici, la variable fn est assignée à une fonction. La raison de ce concept est que les fonctions sont des objets en JavaScript; fn pointe vers l'instance d'objet de la fonction ci-dessus. Nous avons initialisé une fonction et l'avons affectée à une variable. Ce n'est pas l'exécution de la fonction et l'attribution du résultat.

Référence: Syntaxe de déclaration de la fonction JavaScript: var fn = function () {} vs function fn () {}

10
Anoop Rai

Les deux sont différentes façons de définir une fonction. La différence réside dans la façon dont le navigateur interprète et les charge dans un contexte d'exécution. 

Le premier cas concerne les expressions de fonction qui ne se chargent que lorsque l'interpréteur atteint cette ligne de code. Donc, si vous le faites comme suit, vous obtiendrez une erreur indiquant que le functionOne n'est pas une fonction .

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

La raison en est que, sur la première ligne, aucune valeur n'est affectée à functionOne et, par conséquent, elle n'est pas définie. Nous essayons d'appeler cela comme une fonction et nous obtenons donc une erreur.

Sur la deuxième ligne, nous affectons la référence d’une fonction anonyme à functionOne.

Le deuxième cas est celui des déclarations de fonction qui se chargent avant que tout code soit exécuté. Donc, si vous aimez ce qui suit, vous ne recevrez aucune erreur car la déclaration se charge avant l'exécution du code.

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

À propos des performances:

Les nouvelles versions de V8 ont introduit plusieurs optimisations sous le capot, de même que SpiderMonkey.

Il n'y a presque plus de différence entre expression et déclaration. 
L'expression de fonction semble être plus rapide maintenant.

Chrome 62.0.3202 Chrome test

FireFox 55 Firefox test

Chrome Canary 63.0.3225 Chrome Canary test


Anonymous expressions de fonction semblent avoir de meilleures performances contre l'expression de la fonction Named.


Firefox Firefox named_anonymous Chrome Canary Chrome canary named_anonymous Chrome Chrome named_anonymous

8
Panos Kal.

Ils sont assez similaires avec quelques petites différences, la première est une variable assignée à une fonction anonyme (Déclaration de fonction) et la deuxième est le moyen normal de créer une fonction en JavaScript (Déclaration de fonction anonyme), les deux ont un usage, des inconvénients et des avantages. :

1. Expression de fonction

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

Une expression de fonction définit une fonction en tant que partie d'un plus grand syntaxe d'expression (généralement une affectation de variable). Les fonctions défini via les fonctions Les expressions peuvent être nommées ou anonymes. Une fonction Les expressions ne doivent pas commencer par «fonction» (d'où les parenthèses Autour de l'exemple d'invocation automatique ci-dessous).

Assigner une variable à une fonction ne signifie pas Hoisting, car nous savons que les fonctions en JavaScript peuvent Hoist, cela signifie qu'elles peuvent être appelées avant d'être déclarées, alors que les variables doivent être déclarées avant de pouvoir y accéder, nous ne pouvons donc pas accéder à la fonction avant où elle est déclarée, cela pourrait aussi être une façon d'écrire vos fonctions, pour les fonctions qui retournent une autre fonction, ce type de déclaration pourrait avoir un sens, également dans ECMA6 et au-dessus, vous pouvez l'affecter à une fonction de flèche qui peut être utilisé pour appeler des fonctions anonymes. Cette façon de déclarer est également un meilleur moyen de créer des fonctions de constructeur en JavaScript.

2. Déclaration de fonction

function functionTwo() {
    // Some code
}

Une déclaration de fonction définit une variable de fonction nommée sans nécessitant une affectation variable. Les déclarations de fonction se présentent sous la forme les constructions autonomes et ne peuvent pas être imbriquées dans des blocs non fonctionnels . C’est utile de les considérer comme les frères et soeurs des déclarations variables . Tout comme les déclarations de variables doivent commencer par «var», Fonction Les déclarations doivent commencer par «fonction».

C'est la manière habituelle d'appeler une fonction en JavaScript, cette fonction peut être appelée avant même de la déclarer, car toutes les fonctions sont bloquées en JavaScript, mais si vous utilisez 'strict', cela ne fonctionnera pas comme prévu, c'est un bon moyen d'appeler toutes les fonctions normales qui ne sont pas grandes en lignes et ne sont pas non plus une fonction constructeur.

De plus, si vous avez besoin de plus d’informations sur le fonctionnement du levage en JavaScript, visitez le lien ci-dessous:

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

7
Alireza

Ce ne sont que deux manières possibles de déclarer des fonctions et, dans un deuxième temps, vous pouvez utiliser la fonction avant la déclaration.

5
Tao

new Function() peut être utilisé pour transmettre le corps de la fonction dans une chaîne. Et par conséquent, cela peut être utilisé pour créer des fonctions dynamiques. Passer également le script sans l'exécuter.

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

secondFunction()
4
SuperNova

Ceci s'appelle une expression de fonction:

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

Ceci est appelé une déclaration de fonction:

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

J'espère que cela aidera à expliquer quelle est la différence entre l'expression de fonction et la déclaration de fonction et comment les utiliser. Merci.

1
Kean Amaral

Déclaration de fonction de différence et expression de fonction:

Javascript a des fonctions de première classe. Cela signifie qu'ils peuvent être traités comme n'importe quelle autre variable. Les fonctions peuvent être passées comme arguments dans une fonction, être renvoyées par une fonction, et peuvent être stockées dans des variables.

Cependant, stocker une fonction dans une variable (expression de fonction) n'est pas le seul moyen de créer une fonction, vous pouvez également le faire via une déclaration fonction. Voici les principales différences:

  1. Les expressions de fonction peuvent être anonymes alors qu'une déclaration de fonction doit avoir un nom.
  2. Les deux ont une propriété de nom qui est utilisée pour identifier la fonction. La propriété nom d'une expression de fonction est le nom de la variable à laquelle elle est liée, alors que le nom d'une déclaration de fonction est simplement le nom donné.
  3. Les déclarations de fonction sont levées alors que les expressions de fonction ne le sont pas. Seule la variable est hissé pour avoir la valeur de undefined.

Voici un exemple:

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

Expression en JS : Quelque chose qui retourne une valeur 
Exemple: Essayez de suivre les instructions dans la console chrome:

a = 10
output : 10

(1 + 3)
output = 4

Declaration/Statement : Quelque chose qui ne retourne pas de valeur 
Exemple:

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

here (1> 2) est une expression mais le statut 'if' ne l'est pas. Ce ne retourne rien. 


De même, nous avons Fonction Déclaration/Déclaration vs Fonction Expression 
Prenons un exemple:

// 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");
}

Important: Que se passe-t-il lorsque les moteurs JavaScript exécutent le fichier js ci-dessus?.

  • Quand ce js s'exécutera, il se passera ce qui suit:

    1. La mémoire sera créée avec les variables 'a' et 'fun_expression'. Et la mémoire sera créée pour l'instruction de fonction 'fun_declaration'
    2. 'a' sera assigné 'indéfini'. "fun_expression" se verra attribuer "indéfini". 'fun_declaration' sera dans la mémoire dans son intégralité. 
      Remarque: Les étapes 1 et 2 ci-dessus s'appellent «Contexte d'exécution - Phase de création»

Supposons maintenant que nous mettions à jour le js en.

// 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

La sortie mentionnée ci-dessus dans les commentaires devrait être utile pour comprendre la différence entre expression de fonction et déclaration/déclaration de fonction.

0
Santosh Pillai

Un point important à noter est: -

laisser il y a deux fonctions: -

sum(1,2);

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

Dans le cas ci-dessus, il sera donné erreur que cette somme n'est pas définie, mais

sum(1,2);

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

Cette fonction ne provoquera aucune erreur car function hoisting aura lieu dans ce cas.

0
Nitesh Ranjan

Fonctions nommées vs fonctions anonymes

Les expressions de fonctions anonymes sont faciles et faciles à saisir, et de nombreuses bibliothèques et outils ont tendance à encourager ce style de code idiomatique. Cependant, ils ont plusieurs inconvénients à prendre en compte:

  1. Les fonctions anonymes n'ont aucun nom utile à afficher dans les traces de pile, ce qui peut rendre le débogage plus difficile.
  2. Sans nom, si la fonction doit se référer à elle-même, pour la récursivité, etc.
  3. Les fonctions anonymes omettent un nom susceptible de générer un code moins lisible.

Dénomination des expressions de fonction

Fournir un nom pour l'expression de votre fonction résout assez efficacement tous ces inconvénients et ne présente aucun inconvénient tangible. La meilleure pratique consiste à toujours nommer les expressions de votre fonction:

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

Dénomination de l'expression de fonction invoquée immédiate (IIFE): 

var a = 42;

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

Remarque: pour les fonctions assignées à une variable, nommer la fonction, dans ce cas, n’est pas très courant et peut prêter à confusion, dans ce cas, il est préférable d’utiliser la fonction flèche.

0
Shakespear

Je préfère définir la fonction comme variable:

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

Au lieu de:

function first(){
    ....
}

Parce que je peux utiliser des expressions et des décorateurs pour définir la fonction. Par exemple:

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

Aussi avec ES6 c'est beaucoup plus court:

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

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

Une autre différence entre les deux fonctions est que functionOne peut être utilisé en tant que variable pouvant contenir plusieurs fonctions et que functionTwo contient un bloc de code qui est exécuté à la demande. Veuillez vérifier ci-dessous:

   var functionOne = (function() {
      return {

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

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

      }
})();

Vous avez le choix de la fonction à appeler. Par exemple, functionOne.sayHello ou functionOne. redirectPage. Et si vous appelez functionTwo, alors tout le bloc de code sera exécuté.

0
H.Ostwal