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

6876

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 ranger le code et de le rendre plus cohérent.

Le développeur précédent a utilisé deux façons de déclarer des fonctions et je ne peux pas déterminer s'il y a une raison 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?

Richard Garside
la source
199
permadi.com/tutorial/jsFunc/index.html est une très bonne page sur les fonctions javascript
uzay95
68
Cet excellent article sur les expressions de fonctions nommées est lié .
Phrogz
13
@CMS fait référence à cet article: kangax.github.com/nfe/#expr-vs-decl
Upperstage
107
Il y a deux choses dont vous devez être conscient: # 1 En JavaScript, les déclarations sont hissées. Cela signifie que cela var a = 1; var b = 2;devient var a; var b; a = 1; b = 2. Ainsi, lorsque vous déclarez functionOne, il est déclaré mais sa valeur n'est pas définie immédiatement. Alors que functionTwo n'est qu'une déclaration, elle est placée en haut de la portée. # 2 functionTwo vous permet d'accéder à la propriété name et cela aide beaucoup lorsque vous essayez de déboguer quelque chose.
xavierm02
65
Oh et btw, la syntaxe correcte est avec un ";" après la cession et sans après la déclaration. Par exemple , function f(){}vs var f = function(){};.
xavierm02

Réponses:

5047

La différence est qu'il functionOnes'agit d'une expression de fonction et donc uniquement définie lorsque cette ligne est atteinte, alors qu'il functionTwos'agit d'une déclaration de fonction et est définie dès que sa fonction ou son script environnant est exécuté (en raison d'un hissage ).

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

Historiquement, les déclarations de fonctions définies dans les blocs étaient gérées de manière incohérente entre les navigateurs. Le mode strict (introduit dans ES5) a résolu ce problème en délimitant les déclarations de fonction dans leur bloc englobant.

'use strict';    
{ // note this block!
  function functionThree() {
    console.log("Hello!");
  }
}
functionThree(); // ReferenceError

Greg
la source
633
@Greg: Soit dit en passant, la différence n'est pas seulement qu'ils sont analysés à des moments différents. Essentiellement, votre functionOneest simplement une variable à laquelle est affectée une fonction anonyme, alors qu'il functionTwos'agit en fait d'une fonction nommée. Faites appel .toString()aux deux pour voir la différence. Cela est important dans certains cas où vous souhaitez obtenir le nom d'une fonction par programme.
Jason Bunting
6
@ Jason Bunting .. pas sûr de ce que vous voulez en venir ici, .toString () semble renvoyer essentiellement la même valeur (la définition de la fonction) pour les deux: cl.ly/2a2C2Y1r0J451o0q0B1B
Jon z
125
Il y a deux différents. Le premier est un function expressionle second est un function declaration. Vous pouvez en savoir plus sur le sujet ici: javascriptweblog.wordpress.com/2010/07/06/…
Michal Kuklis
128
@Greg La partie de votre réponse concernant le temps d'analyse vs le temps d'exécution n'est pas correcte. En JavaScript, les déclarations de fonction ne sont pas définies pendant le temps d'analyse, mais pendant l'exécution. Le processus se déroule comme suit: Le code source est analysé -> Le programme JavaScript est évalué -> Le contexte d'exécution global est initialisé -> L'instanciation de la liaison de déclaration est effectuée. Au cours de ce processus, les déclarations de fonctions sont instanciées (voir l'étape 5 du chapitre 10.5 ).
Šime Vidas
103
La terminologie de ce phénomène est connue sous le nom de levage.
Colin Pear
1944

Je veux d'abord corriger Greg: function abc(){}est également abcdélimité - le nom 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(){};

xyzva être défini comme d'habitude, abcn'est pas défini dans tous les navigateurs, mais Internet Explorer - ne comptez pas sur 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 alias des fonctions sur tous les navigateurs, utilisez ce type de déclaration:

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

Dans ce cas, les deux xyzet abcsont des alias du même objet:

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

Une raison impérieuse d'utiliser le style combiné est l'attribut "nom" des objets fonction ( non pris en charge par Internet Explorer ). 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 assignée à une variable.

Une autre bonne raison d'utiliser le style combiné est d'utiliser un nom interne court pour se référer à 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 de même avec un nom externe, mais ce sera trop lourd (et plus lent).

(Une autre façon de se référer à lui-même est d'utiliser arguments.callee, qui est encore relativement longue et non prise en charge en mode strict.)

Au fond, JavaScript traite les deux déclarations différemment. Ceci est une déclaration de fonction:

function abc(){}

abc ici est défini partout dans le périmètre actuel:

// 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 a été hissé à travers une returndéclaration:

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

Il s'agit d'une expression de fonction:

var xyz = function(){};

xyz ici 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 vs expression de fonction est la vraie raison pour laquelle il y a une différence démontrée par Greg.

Fait amusant:

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

Personnellement, je préfère la déclaration "expression de fonction" car de cette façon je peux 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 le définir abcnulle part dans la chaîne des étendues. Ce style de définition est résistant même lorsqu'il est utilisé à l'intérieur eval(). Bien 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.

Eugene Lazutkin
la source
70
Je me réfère à RoBorg mais il est introuvable. Simple: RoBorg === Greg. C'est ainsi que l'histoire peut être réécrite à l'ère d'Internet. ;-)
Eugene Lazutkin
10
var xyz = fonction abc () {}; console.log (xyz === abc); Tous les navigateurs que j'ai testés (Safari 4, Firefox 3.5.5, Opera 10.10) me donnent "Variable non définie: abc".
NVI
7
Dans l'ensemble, je pense que ce message explique bien les différences et les avantages de l'utilisation de la déclaration de fonction. Je serai d'accord pour ne pas être d'accord sur les avantages de l'utilisation des affectations d'expressions de fonctions à une variable, d'autant plus que le "bénéfice" semble être une provocation de la déclaration d'une entité globale ... et tout le monde sait que vous ne devriez pas encombrer l'espace de noms global , droite? ;-)
natlee75
84
imo une raison énorme d'utiliser la fonction nommée est que les débogueurs peuvent utiliser le nom pour vous aider à comprendre votre pile d'appels ou votre trace de pile. ça craint quand vous regardez la pile des appels et voyez "la fonction anonyme" 10 niveaux de profondeur ...
chèvre
3
var abc = function(){}; console.log(abc.name);ne produit ""plus, mais à la "abc"place.
Qwerty
633

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

  • functionExpression "anonyme" (qui malgré le terme, crée parfois des fonctions avec des noms)

  • functionExpression nommée

  • Initialiseur de fonction d'accesseur (ES5 +)

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

  • Déclaration de méthode dans l'initialiseur d'objet (ES2015 +)

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

Déclaration de fonction

Le premier formulaire 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 cela soit inoffensif).

Une déclaration de fonction est traitée lorsque l'exécution entre dans le contexte dans lequel elle apparaît, avant l' exécution de tout code étape par étape. La fonction qu'elle 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.

Parce qu'il est traité avant tout code étape par étape dans le même contexte, vous pouvez faire des choses comme ceci:

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

Jusqu'à ES2015, la spécification ne couvre pas ce que l' intérieur d' une structure de contrôle comme un moteur JavaScript doit faire si vous mettez une déclaration de fonction try, if, switch, while, etc., comme ceci:

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

Et comme ils sont traités avant l' exécution du code étape par étape, il est difficile de savoir quoi faire lorsqu'ils sont dans une structure de contrôle.

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

Depuis ES2015, la spécification indique ce qu'il faut faire. En fait, cela donne trois choses distinctes à faire:

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

Les règles pour les modes lâches sont délicates, mais en mode strict , les déclarations de fonctions dans les blocs sont faciles: elles sont locales au bloc (elles ont une portée de bloc , qui est également nouvelle dans ES2015), et elles sont hissées vers le haut du bloc. Donc:

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

functionExpression "anonyme"

La deuxième forme courante est appelée une expression de fonction anonyme :

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

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

Dans ES5, la fonction ainsi créée n'a pas de nom (elle est anonyme). Dans ES2015, la fonction se voit attribuer un nom si possible en le déduisant 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 SetFunctionNamedans la spécification  - elle apparaît partout .)

functionExpression nommée

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

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

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

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

Notez que les NFE ont souvent été une source de bogues pour les implémentations JavaScript. IE8 et les versions antérieures, par exemple, gèrent les NFE de manière complètement incorrecte , 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 plus, Safari actuel) n'ont plus ces problèmes. (Mais à ce jour, malheureusement, IE8 reste largement utilisé, et donc l'utilisation d'ENF avec du code pour le Web en général reste problématique.)

Initialiseur de fonction d'accesseur (ES5 +)

Parfois, les fonctions peuvent passer inaperçues en grande partie; c'est le cas des fonctions d'accesseur . 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 ne l'ai pas utilisée ()! C'est parce que c'est une fonction d'accesseur pour une propriété. Nous obtenons et définissons la propriété de la manière normale, mais en arrière-plan, la fonction est appelée.

Vous pouvez également créer des accesseurs fonctions avec Object.defineProperty, Object.definePropertieset le second argument moins connu pour Object.create.

Expression de la fonction flèche (ES2015 +)

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

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

Vous voyez cette n => n * 2chose qui se cache dans l' map()appel? C'est une fonction.

Quelques choses sur les fonctions fléchées:

  1. Ils n'ont pas les leurs this. Au lieu de cela, ils près sur le thisdu contexte dans lequel elles sont définies. (Ils se ferment également argumentset, le cas échéant,. super) Cela signifie que l' thisintérieur d'eux est le même que l' thisendroit où ils ont été créés et ne peut pas être modifié.

  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' n => n * 2exemple 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

(N'oubliez pas que Array#mappasse l'entrée comme premier argument et l'index comme deuxième.)

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 d'explicite return).

Si vous faites plus qu'une simple expression, utilisez {}et une explicite return(si vous devez retourner 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 { ... }est appelée fonction de flèche avec un corps d'expression ou un corps concis . (Aussi: Une fonction de flèche concise .) Celui qui { ... }définit le corps est une fonction de flèche avec un corps de fonction . (Aussi: Une fonction de flèche verbeuse .)

Déclaration de méthode dans l'initialiseur d'objet (ES2015 +)

ES2015 permet une forme plus courte de déclaration d'une propriété qui fait référence à une fonction appelée définition de méthode ; cela ressemble à ceci:

var o = {
    foo() {
    }
};

le quasi-équivalent dans ES5 et les versions antérieures 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 (disons) en valueOfutilisant la syntaxe de la méthode, il pourrait utiliser super.valueOf()pour obtenir la valeur Object.prototype.valueOfserait retourné (avant de faire probablement autre chose avec lui), alors que la version ES5 devrait le faire à la Object.prototype.valueOf.call(this)place.

Cela signifie également que la méthode a une référence à l'objet sur lequel elle a été définie, donc si cet objet est temporaire (par exemple, vous le transmettez Object.assigncomme l'un des objets source), la syntaxe de la méthode pourrait signifier 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 la gère si aucune des méthodes ne l'utilise super).

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

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

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 obtient le nom Person, et une pour getFullName, qui est une fonction affectée à Person.prototype.

TJ Crowder
la source
3
alors le nom west simplement ignoré?
BiAiB
8
@PellePenna: Les noms de fonction sont utiles pour beaucoup de choses. À mon avis, les deux biggies sont la récursivité et le nom de la fonction affiché dans les piles d'appels, les traces d'exception, etc.
TJ Crowder
4
@ChaimEliyah - "Accepter ne signifie pas que c'est la meilleure réponse, cela signifie simplement que cela a fonctionné pour la personne qui a demandé." source
ScrapCode
6
@AR: Tout à fait vrai. De manière amusante, cependant, juste au-dessus de cela, il est dit "Les meilleures réponses apparaissent en premier afin qu'elles soient toujours faciles à trouver." Étant donné que la réponse acceptée apparaît en premier, même par rapport aux réponses plus votées, la visite peut être quelque peu contradictoire. ;-) Aussi un peu inexact, si nous déterminons le "meilleur" par les votes (ce qui n'est pas fiable, c'est juste ce que nous avons), les "meilleures" réponses n'apparaissent en premier que si vous utilisez l'onglet "Votes" - sinon, les premières réponses sont les réponses actives ou les plus anciennes.
TJ Crowder
1
@TJCrowder: D'accord. «organisé par date» est parfois ennuyeux.
ScrapCode
145

En parlant du contexte global, à la fois, l' varinstruction et un FunctionDeclarationà la fin créeront une propriété non supprimable sur l'objet global, mais la valeur des deux peut être écrasée .

La différence subtile entre les deux façons est que lorsque le processus d' instanciation variable s'exécute (avant l'exécution du code réel) tous les identifiants déclarés avec varseront initialisés avec undefined, et ceux utilisés par les FunctionDeclarationseront disponibles depuis ce moment, 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 du bar FunctionExpressionse déroule jusqu'à l'exécution.

Une propriété globale créée par un FunctionDeclarationpeut être remplacée sans aucun problème 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 la seconde l'a, ce qui peut être très utile lors du débogage (c'est-à-dire inspecter une pile d'appels).

À propos de votre premier exemple modifié (foo = function() { alert('hello!'); }; ), il s'agit d'une affectation non déclarée, je vous encourage vivement à toujours utiliser le varmot - clé.

Avec une mission, sans var instruction, si l'identifiant référencé ne se trouve pas dans la chaîne de portée, il deviendra une propriété supprimable de l'objet global.

En outre, les affectations non déclarées jettent un ReferenceError ECMAScript 5 en mode strict .

À lire absolument:

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

CMS
la source
Je ne savais pas que les fonctions pouvaient être écrasées en JavaScript! De plus, cet ordre d'analyse est le principal argument de vente pour moi. Je suppose que je dois regarder comment je crée des fonctions.
Xeoncross
2
+0 à l'article "Expressions de fonction de noms démystifiées" car il s'agit de 404ing. Miroir possible?: Kangax.github.com/nfe
Mr_Chimp
@CMS Nice one. Gardez à l'esprit que je n'ai jamais vu l'original, donc je ne sais pas si c'est un miroir ou juste un autre article avec le même titre!
Mr_Chimp
@Mr_Chimp Je suis sûr que c'est le cas, thewaybackmachine dit qu'il a obtenu un 302 au moment de l'exploration et la redirection a été vers le lien que vous avez fourni.
John
125

Les deux extraits de code que vous y avez publiés se comporteront, à presque toutes les fins, de la même manière.

Cependant, la différence de comportement est 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 au-dessus de l'endroit où la fonction est déclarée.

En effet, avec la première variante, la fonction est affectée à la variable fooau moment de l'exécution. Dans le second, 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 les fonctions.

  1. Votre premier extrait de code affiche une expression de fonction . Cela implique l'utilisation de l' opérateur "fonction" pour créer une fonction - le résultat de cet opérateur peut être stocké dans n'importe quelle variable ou propriété 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 d'avoir de nom,
  2. Votre deuxième exemple est une déclaration de fonction . Cela 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 façon de définir une fonction est le constructeur "Function ()" , qui n'est pas montré dans votre message d'origine. Il n'est pas recommandé de l'utiliser car il fonctionne de la même manière que eval(), ce qui a ses problèmes.
thomasrutter
la source
104

Une meilleure explication à la 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 fonctions et les déclarations de variables sont toujours déplacées ( hoisted) de manière invisible en haut de leur portée contenante par l'interpréteur JavaScript. Les paramètres de fonction et les noms définis par le langage sont évidemment déjà là. ben cherry

Cela signifie que le code comme celui-ci:

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

Notez que la partie affectation des déclarations n'a pas été hissée. Seul le nom est hissé.

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

functionTwo();              ---------------      function functionTwo() {
                            | is actually |      };
function functionTwo() {    | interpreted |-->
}                           |    like     |      functionTwo();
                            ---------------
suhailvs
la source
HI suhail merci pour des informations claires sur le sujet de la fonction. Maintenant, ma question est laquelle sera la première déclaration dans la hiérarchie de déclaration, que ce soit la déclaration de variable (functionOne) ou la déclaration de fonction (functionTwo)?
Sharathi RB
91

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 variation "affectation" peut définir une propriété d'un autre objet.

Je construis souvent des modules JavaScript avec un modèle comme celui-ci:

(function(){
    var exports = {};

    function privateUtil() {
            ...
    }

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

    return exports;
})();

Avec ce modèle, vos fonctions publiques utiliseront toutes l'affectation, tandis que vos fonctions privées utiliseront la déclaration.

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

Sean McMillan
la source
4
yuiblog.com/blog/2007/06/12/module-pattern est la référence primordiale pour le modèle de module, pour autant que je sache. (Bien que cet article utilise la var foo = function(){...}syntaxe même pour les variables privées.
Sean McMillan
Ce n'est pas entièrement vrai dans certaines anciennes versions d'IE, en fait. ( function window.onload() {}était une chose.)
Ry-
77

Une illustration de quand préférer la première méthode à la seconde est quand vous devez éviter de remplacer les définitions précédentes d'une fonction.

Avec

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

, cette définition de myfunctionremplacera 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
    }
}

fait le travail correct de définir myfunctionuniquement quand conditionest atteint.

Mbengue Assane
la source
1
cet exemple est bon et proche de la perfection, mais pourrait être amélioré. le meilleur exemple serait de définir en var myFunc = null;dehors d'une boucle, ou en dehors d'un bloc if / elseif / else. Vous pouvez ensuite affecter conditionnellement différentes fonctions à la même variable. Dans JS, il est préférable d'assigner une valeur manquante à null, puis à undefined. Par conséquent, vous devez d'abord déclarer myFunction comme nulle, puis l'affecter ultérieurement, conditionnellement.
Alexander Mills
62

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 d'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?

Rob
la source
3
Il semble que cette réponse ait été fusionnée dans cette question à partir d'une autre question, et le libellé peut sembler être un tout petit peu sans rapport avec cette question. Envisageriez-vous de modifier la réponse pour qu'elle semble plus orientée spécifiquement vers cette question? (pour réitérer; ce n'est pas du tout votre faute ... juste un effet secondaire d'une question fusionnée). Vous pouvez également le supprimer et je pense que vous conserverez votre réputation. Ou vous pouvez le laisser; comme il est vieux, cela ne fera peut-être pas une grande différence.
Andrew Barber
55

Le levage est l'action de l'interpréteur JavaScript de déplacer toutes les déclarations de variables et de fonctions en haut de la portée actuelle.

Cependant, seules les déclarations réelles sont hissées. en laissant les affectations là où elles sont.

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

Variable

Javascript est appelé langage peu typé. Ce qui signifie que les variables Javascript peuvent contenir la valeur de n'importe quel type de données . Javascript prend automatiquement en charge la modification du 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 ayant un accès global.
  • les fonctions déclarées à l'intérieur du bloc fonction sont hissées en haut du bloc.
  • La valeur de retour par défaut de la fonction est « non définie », la valeur par défaut de la déclaration de variable est également «non définie»

    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

Expression de fonction

        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 affecté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, le test d'expression sur différents navigateurs en utilisant jsperf Test Runner


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

JavaScript traite les fonctions comme des objets de première classe. 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 a introduit la fonction Flèche : une expression de fonction Flèche a une syntaxe plus courte, elle est mieux adaptée aux fonctions non-méthode et ne peut pas être utilisée comme constructeur.

ArrowFunction : ArrowParameters => ConciseBody.

const fn = (item) => { return item & 1 ? 'Odd' : 'Even'; };
console.log( fn(2) ); // Even
console.log( fn(3) ); // Odd
Yash
la source
3
ahm, votre réponse ... n'est-ce pas ambigu? bien écrit, donc +1 pour les dépenses et l'écriture de trop d'informations.
Danois
40

J'ajoute ma propre réponse juste parce que tout le monde a soigneusement couvert la partie de levage.

Je me demande depuis longtemps quel est le meilleur chemin, et grâce à http://jsperf.com maintenant je sais :)

entrez la description de l'image ici

Les déclarations de fonctions sont plus rapides, et c'est ce qui compte vraiment dans le développement Web, non? ;)

Leon Gaban
la source
8
Je dirais que la maintenabilité est l'aspect le plus important de la plupart des codes. Les performances sont importantes, mais dans la plupart des cas, les E / S sont susceptibles d'être un goulot d'étranglement plus important que la façon dont vous définissez vos fonctions. Cependant, il y a certains problèmes où vous avez besoin de chaque bit de performance que vous pouvez obtenir et cela est utile dans ces cas. Il est également bon d'avoir une réponse ici qui répond clairement à une partie bien définie de la question.
Richard Garside
3
Eh bien, j'ai trouvé que c'était l'inverse avec Firefox. jsperf.com/sandytest
Sandeep Nayak
Juste une mise à jour, depuis que je suis devenu un style de programmation fonctionnel complet en JavaScript maintenant, je n'utilise jamais de déclarations, seulement des expressions de fonction pour pouvoir enchaîner et appeler mes fonctions par leurs noms de variables. Découvrez RamdaJS ...
Leon Gaban
1
@SandeepNayak Je viens de lancer votre propre test dans Firefox 50.0.0 / Windows 7 0.0.0, et c'est en fait la même chose que Leon. Donc, si votre test est correct, je conclurais que les tests de jsperf ne sont pas indicatifs, et tout dépend de votre navigateur et / ou de la version du système d'exploitation, ou de l'état particulier de la machine actuelle à ce moment particulier.
ocramot
33

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

Il existe cependant une différence quant à la manière et au moment où l'objet fonction est réellement associé à sa variable. Cette différence est due au mécanisme appelé levage variable en JavaScript.

Fondamentalement, toutes les déclarations de fonctions et les déclarations de variables sont hissées au sommet de la fonction dans laquelle la déclaration se produit (c'est pourquoi nous disons que JavaScript a une portée de fonction ).

  • Lorsqu'une déclaration de fonction est hissée, le corps de la fonction "suit", donc lorsque le corps de la fonction est évalué, la variable sera immédiatement liée à un objet fonction.

  • Lorsqu'une déclaration de variable est hissée, l'initialisation ne suit pas , mais est "laissée pour compte". La variable est initialisée undefinedau début du corps de la fonction et se verra attribuer une valeur à son emplacement d'origine dans le code. (En fait, une valeur lui sera attribuée à chaque emplacement où se produit la déclaration d'une variable du même nom.)

L'ordre de levage est également important: les déclarations de fonctions ont priorité sur les déclarations de variables portant le même nom et la dernière déclaration de fonctions a priorité sur les déclarations de fonctions 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 fooest hissée en haut de la fonction, initialisée à undefined, c'est-à- !foodire qu'elle est truedonc fooaffectée 10. L' fooextérieur de barla portée de ne joue aucun rôle et reste intact.

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 fonctions ont priorité sur les déclarations de variables et la dernière déclaration de fonction "colle".

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

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

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

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

eljenso
la source
3
Vous avez une façon un peu bizarre de placer les accolades de fermeture. Êtes-vous un codeur Python? Il semble que vous essayez de faire en sorte que Javascript ressemble à Python. J'ai peur que ce soit déroutant pour les autres. Si je devais maintenir votre code JavaScript, je laisserais d'abord votre code passer par une jolie imprimante automatique.
nalply
1
Excellent poste. Une «fonction auto-exécutable» ou une «expression de fonction immédiatement invoquée» devrait être assez facile à voir et sa préférence de style ne devrait pas nuire à son message - ce qui est précis et résume parfaitement le «levage». +1
Ricalsin
32

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 est de savoir comment ils sont hissés (levés et déclarés). Dans le premier exemple, la déclaration de fonction entière est hissée. Dans le deuxième exemple, seul le var 'abc' est hissé, sa valeur (la fonction) sera indéfinie et la fonction elle-même reste à la position où elle est 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 recommande fortement ce lien

sla55er
la source
1
Votre exemple est un peu la même que la première réponse
GôTô
La raison principale de la publication de cette réponse était de fournir le lien en bas. C'était le morceau qui me manquait pour bien comprendre la question ci-dessus.
sla55er
1
C'est très cool que vous vouliez partager le lien. Mais les liens vers des informations supplémentaires, dans SO, ne devraient être qu'un commentaire sur la question ou votre réponse préférée. Il est très sous-optimal d'encombrer une longue page compliquée comme celle-ci avec des informations répétées juste pour ajouter un seul lien utile à la fin. Non, vous n'obtiendrez pas de points de représentation pour avoir fourni le lien, mais vous aiderez la communauté.
XML
31

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

  • Indépendant de l'endroit où ils sont déclarés (mais toujours limité par la portée).
  • Plus résistant aux erreurs comme l'initialisation conditionnelle (vous pouvez toujours remplacer si vous le souhaitez).
  • Le code devient plus lisible en allouant des fonctions locales séparément de la fonctionnalité de portée. Habituellement, dans la portée, la fonctionnalité passe en premier, suivie des 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 sont apparues à cause de l'incapacité de JavaScript en tant que langage à répertorier les membres avec des fonctions nommées:

{
    member:function() { /* How do I make "this.member" a named function? */
    }
}
Sasha Firsov
la source
2
Il y a le test à confirmer: blog.firsov.net/2010/01/… Test de performance JS - portée et fonctions nommées - Analytique
Sasha Firsov
25

En termes informatiques, nous parlons 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 lors 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 ).

Kafka
la source
Depuis ES2015 (six ans et demi après la publication de votre réponse), les deux fonctions de la question sont nommées.
TJ Crowder
25

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 JavaScript limitée.

J'ai du code que je dois exécuter avec 160 marques conçues indépendamment. La plupart du code se trouve dans des fichiers partagés, mais les éléments spécifiques à la marque se trouvent dans un fichier distinct, 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 codage partagé, mais je ne veux pas avoir à changer les 160 ensembles de fichiers de marque.

En utilisant la syntaxe des variables, je peux déclarer la variable (un pointeur de fonction essentiellement) dans le code partagé et soit attribuer une fonction de remplacement triviale, soit définir sur null.

Le ou les deux brandings qui ont besoin d'une implémentation spécifique de la fonction peuvent alors définir leur version de la fonction et l'affecter à la variable s'ils le souhaitent, et les autres ne font rien. Je peux tester une fonction nulle avant de l'exécuter dans le code partagé.

D'après les commentaires des gens ci-dessus, je suppose qu'il est également possible de redéfinir une fonction statique, mais je pense que la solution variable est agréable et claire.

Herc
la source
25

La réponse de Greg est assez bonne, mais je voudrais quand même ajouter quelque chose que j'ai appris tout à l'heure en regardant les vidéos de Douglas Crockford .

Expression de fonction:

var foo = function foo() {};

Énoncé de fonction:

function foo() {};

L'instruction de fonction n'est qu'un raccourci pour une varinstruction avec une functionvaleur.

Donc

function foo() {};

s'étend à

var foo = function foo() {};

Qui s'étend encore à:

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

Et ils sont tous les deux hissés en haut du code.

Capture d'écran de la vidéo

Rohan
la source
7
Désolé mais c'est incorrect - je ne sais pas ce que Crockford essaie de dire dans cette diapositive. Les déclarations de fonction et de variable sont toujours hissées au sommet de leur portée. La différence est que les affectations de variables (que vous l'affectiez avec une chaîne, un booléen ou une fonction) ne soient pas hissées vers le haut, contrairement aux corps de fonction (à l'aide de la déclaration de fonction).
Thomas Heymann
Jetez un œil à ces exemples de code: gist.github.com/cyberthom/36603fbc20de8e04fd09
Thomas Heymann
24

Il existe quatre comparaisons notables entre les deux différentes déclarations de fonctions énumérées ci-dessous.

  1. Disponibilité (portée) de la fonction

Ce qui suit fonctionne car function add()est limité au bloc le plus proche:

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

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

Ce qui suit ne fonctionne pas car la variable est appelée avant qu'une valeur de fonction ne soit affectée à la variable add.

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

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

Le code ci-dessus a une fonctionnalité identique au code ci-dessous. Notez que l'affectation explicite add = undefinedest superflue car simplement faire var add;est exactement la même chose que var add=undefined.

var add = undefined;

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

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

Ce qui suit ne fonctionne pas car le var add=super-ensemencement le function add().

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

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

  1. (fonction) .name

Le nom d'une fonction function thefuncname(){}est thefuncname quand elle est déclarée de cette façon.

function foobar(a, b){}

console.log(foobar.name);

var a = function foobar(){};

console.log(a.name);

Sinon, si une fonction est déclarée comme function(){}, la fonction .name est la première variable utilisée pour stocker la fonction.

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

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

S'il n'y a pas de variables définies pour la fonction, alors le nom des fonctions est la chaîne vide ( "").

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

Enfin, alors que la variable à laquelle la fonction est affectée définit initialement le nom, les variables successives définies sur la fonction ne changent pas le nom.

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

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

  1. Performance

Dans le V8 de Google et Spidermonkey de Firefox, il pourrait y avoir quelques différences de compilation JIST en quelques microsecondes, mais en fin de compte, le résultat est exactement le même. Pour le prouver, examinons l'efficacité de JSPerf aux microbenchmarks en comparant la vitesse de deux extraits de code vierges. Les tests JSPerf se trouvent ici . Et, les tests jsben.ch se trouvent ici . Comme vous pouvez le voir, il y a une différence notable quand il ne devrait pas y en avoir. Si vous êtes vraiment un monstre de performance comme moi, cela vaut peut-être mieux que vous essayiez de réduire le nombre de variables et de fonctions dans la portée et surtout d'éliminer le polymorphisme (comme utiliser la même variable pour stocker deux types différents).

  1. Mutabilité variable

Lorsque vous utilisez le varmot clé pour déclarer une variable, vous pouvez ensuite réaffecter une valeur différente à la variable comme ceci.

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

Cependant, lorsque nous utilisons l'instruction const, la référence de variable devient immuable. Cela signifie que nous ne pouvons pas affecter une nouvelle valeur à la variable. Veuillez noter, cependant, que cela ne rend pas le contenu de la variable immuable: si vous le faites const arr = [], vous pouvez toujours le faire arr[10] = "example". Faire seulement quelque chose comme arr = "new value"ou arr = []lancerait une erreur comme vu ci-dessous.

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

Fait intéressant, si nous déclarons la variable comme function funcName(){}, alors l'immuabilité de la variable est identique à la déclarer avec var.

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

Quel est le "bloc le plus proche"

Le "bloc le plus proche" est la "fonction" la plus proche (y compris les fonctions asynchrones, les fonctions de générateur et les fonctions de générateur asynchrone). Cependant, il est intéressant de noter qu'un a function functionName() {}se comporte comme un var functionName = function() {}élément dans un bloc sans fermeture vis-à-vis des articles en dehors de ladite fermeture. Observer.

  • Ordinaire 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}

  • Ordinaire 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;
}

  • Une fonction

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

  • Déclaration (tels que if, else, for, while, try/ catch/ finally, switch, do/ while, with)

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

  • Fonction flèche avec 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;
    }
})();

  • Fonction flèche avec 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;
    }
})();

Jack Giffin
la source
Cela mérite d'être la réponse acceptée et la plus votée
Aaron John Sabu
18

@EugeneLazutkin donne un exemple où il nomme une fonction assignée pour pouvoir l'utilisershortcut() comme référence interne à lui-même. John Resig donne un autre exemple: copier une fonction récursive affectée à un autre objet dans son Learning Advanced Javascript didacticiel . Bien que l'attribution de fonctions aux propriétés ne soit pas strictement la question ici, je recommande d'essayer activement le didacticiel - exécutez le code en cliquant sur le bouton dans le coin supérieur droit et double-cliquez sur le code pour le modifier à votre guise.

Exemples du tutoriel: 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 récursivement, 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." );
Joel Purra
la source
17

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 constructeur comme dans

var one = new functionOne();

alors one.constructor.namene sera pas défini. Function.namen'est pas standard mais est pris en charge 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.

Ingo Kegel
la source
Le nom dans le premier cas ne sera pas défini car il s'agit d'une fonction anonyme affectée à une variable. Je pense que le mot anonyme a été inventé pour des choses qui n'ont pas leur nom défini :)
Om Shankar
Dans cet exemple, les deux = nouveaux deviennent une fonction globale car aucun var
Waqas Tahir
16

La première (fonction doSomething (x)) doit faire partie d'une notation d'objet.

Le second ( var doSomething = function(x){ alert(x);}) crée simplement une fonction anonyme et l'affecte à une variable,doSomething . Donc, doSomething () appellera la fonction.

Vous voudrez peut-être savoir ce qu'une déclaration de fonction et une 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 se produisent en tant que 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
identificateur de fonction (FormalParameterList opt ) {FunctionBody}

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

Et dans une expression de fonction

Une expression de fonction définit une fonction comme faisant partie d'une syntaxe d'expression plus large (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
identifiant de fonction opt (FormalParameterList opt ) {FunctionBody}

NullPoiиteя
la source
16

Je liste les différences ci-dessous:

  1. Une déclaration de fonction peut être placée n'importe où dans le code. Même si elle est invoquée avant que la définition n'apparaisse dans le code, elle est exécutée lorsque la déclaration de fonction est validée en mémoire ou d'une manière telle qu'elle est hissée, avant que tout autre code de la page ne commence son exécution.

    Jetez un œil à la fonction ci-dessous:

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

    En effet, lors de l'exécution, il 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. Ici aussi, la définition de la fonction elle-même n'est pas déplacée vers le haut ou enregistrée dans la mémoire comme dans les déclarations de fonction. Mais la variable à laquelle nous attribuons la fonction est hissée et undefined lui est assigné.

    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, lors de 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 n'est pas sûr d'écrire des déclarations de fonctions dans des blocs non fonctionnels comme si 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()}
varna
la source
1
@Arjun Quel est le problème si une question a été posée des années plus tôt? Une réponse ne profite pas seulement à l'OP mais potentiellement à tous les utilisateurs SO, peu importe quand la question a été posée. Et qu'y a-t-il de mal à répondre à des questions qui ont déjà une réponse acceptée?
SantiBailors
1
@Arjun, vous avez compris que répondre à de vieilles questions n'est pas mauvais. S'il en était ainsi, SO aurait eu une telle barrière. Imaginez qu'il y ait un changement dans l'API (bien que ce ne soit pas dans le contexte de cette question) et que quelqu'un le repère et fournisse une réponse avec la nouvelle API, cela ne devrait-il pas être autorisé ?? Tant que la réponse n'a pas de sens et n'appartient pas ici, elle sera automatiquement rejetée et supprimée automatiquement. Vous n'avez pas besoin de vous en soucier !!!!
Sudhansu Choudhary
15

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
Pawel Furmaniak
la source
Je n'arrive pas à reproduire cela. console.log(objectOne.__proto__);affiche "functionOne {}" dans ma console. Des idées sur la raison pour laquelle cela peut être le cas?
Mike
Je n'arrive pas à le reproduire aussi.
daremkd
1
C'est une capacité de votre débogueur (pour afficher la "classe" de l'objet journalisé), et la plupart d'entre eux sont capables de dériver un nom même pour les expressions de fonction anonymes de nos jours. Btw, vous devez préciser qu'il n'y a pas de différence fonctionnelle entre les deux instances.
Bergi
12

À 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.

À ce jour, V8, SpiderMonkey, Chakra et Nitro se réfèrent toujours aux fonctions nommées par leurs noms. Ils se réfèrent presque toujours à une fonction anonyme par son identifiant si elle en possède une.

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 votre itérateur et vos rappels de succès apparaissent dans la trace, vous pouvez aussi les nommer ...

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

Mais pour la plupart, cela ne vaut pas la peine d'être souligné.

Harnais ( violon )

'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
Jackson
la source
12

En JavaScript, il existe deux façons 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é qu'une fonction l'avait définie et exécutée en l'appelant.

    Ce que vous devez savoir, c'est que les fonctions sont en fait des objets en JavaScript; en interne, nous avons créé un objet pour la fonction ci-dessus et lui avons donné 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 fait une instance d'objet.

  2. Expression de 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 affecté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 assignée à une variable. Il ne s'agit pas d'exécuter la fonction et d'attribuer le résultat.

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

Anoop Rai
la source
1
qu'en est-il de la troisième option var fn = function fn() {...},?
chharvey
Salut Chharvey, pas sûr de ta question, je suppose que tu parles de l'expression de fonction que j'ai déjà mentionnée. Cependant, s'il y a encore une certaine confusion, soyez plus détaillé.
Anoop Rai
oui, je demandais une expression de fonction nommée . c'est similaire à votre option # 2 sauf que la fonction a un identifiant. cet identifiant est généralement le même que la variable à laquelle il est affecté, mais ce n'est pas toujours le cas.
chharvey
1
Oui L'expression de fonction nommée est similaire à mon option # 2. Bien avoir un identifiant n'est pas obligatoire car il n'est pas utilisé. Chaque fois que vous exécuterez l'expression de fonction, vous utiliserez la variable contenant l'objet de fonction. L'identifiant ne sert à rien.
Anoop Rai
11

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

Le premier cas est celui des 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 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 donc elle n'est pas définie. Nous essayons de l'appeler en tant que fonction, et donc nous obtenons une erreur.

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

Le deuxième cas est celui des déclarations de fonctions qui se chargent avant l'exécution de tout code. Donc, si vous aimez ce qui suit, vous n'obtiendrez aucune erreur lors du chargement de la déclaration avant l'exécution du code.

functionOne();
function functionOne() {
   // Some code
}
Nitin9791
la source
11

À propos des performances:

De nouvelles versions de V8introduit plusieurs optimisations sous le capot et ainsi de suite SpiderMonkey.

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

Chrome 62.0.3202 Test Chrome

FireFox 55 Test Firefox

Chrome Canary 63.0.3225 Test Chrome Canary


Anonymousles expressions de fonction semblent avoir de meilleures performances par rapport à Namedl'expression de fonction.


Firefox Chrome Canary ChromeFirefox named_anonymous Canari Chrome nommé_anonyme Chrome named_anonymous

Panos Kal.
la source
1
Oui, cette différence est si insignifiante que, espérons-le, les développeurs se préoccuperont de l'approche la plus maintenable pour leurs besoins spécifiques plutôt que de celle qui pourrait être plus rapide (vous obtiendrez des résultats jsperf différents à chaque essai en fonction de ce que fait le navigateur - la majorité des tâches javascript n'ont pas à se préoccuper de micro-optimisations à ce degré).
squidbe
@squidbe Il n'y a aucune différence. Regardez ici: jsperf.com/empty-tests-performance
Jack Giffin
10

Ils sont assez similaires avec quelques petites différences, la première est une variable qui est affectée à une fonction anonyme (Déclaration de fonction) et la seconde est la manière normale de créer une fonction en JavaScript (Déclaration de fonction anonyme), les deux ont une utilisation, des inconvénients et des avantages :

1. Expression de fonction

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

Une expression de fonction définit une fonction comme faisant partie d'une syntaxe d'expression plus large (généralement une affectation de variable). Les fonctions définies via Functions Les expressions peuvent être nommées ou anonymes. Les expressions de fonction ne doivent pas commencer par «fonction» (d'où les parenthèses autour de l'exemple d'auto-invocation ci-dessous).

Assigner une variable à une fonction, signifie pas de levage, comme nous savons que les fonctions JavaScript peuvent Hoist, cela signifie qu'elles peuvent être appelées avant d'être déclarées, tandis que les variables doivent être déclarées avant d'y accéder, ce qui signifie que dans ce cas, nous ne pouvons pas accéder à la fonction avant l'endroit où elle est déclarée, cela pourrait également être un moyen d'écrire vos fonctions, pour les fonctions qui renvoient une autre fonction, ce type de déclaration pourrait avoir du sens, également dans ECMA6 et ci-dessus, vous pouvez l'assigner à une fonction de flèche qui peut être utilisé pour appeler des fonctions anonymes, également cette façon de déclarer est une meilleure façon de créer des fonctions Constructor 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écessiter d'affectation de variable. Les déclarations de fonctions se produisent en tant que constructions autonomes et ne peuvent pas être imbriquées dans des blocs non fonctionnels. Il est utile de les considérer comme des frères et sœurs de déclarations de variables. Tout comme les déclarations de variables doivent commencer par «var», les déclarations de fonctions doivent commencer par «function».

C'est la façon normale d'appeler une fonction en JavaScript, cette fonction peut être appelée avant même de la déclarer car en JavaScript toutes les fonctions sont hissées, mais si vous avez 'utiliser strict' cela ne sera pas Hoist comme prévu, c'est un bon moyen pour 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

Alireza
la source
1
...also this way of declaring is a better way to create Constructor functions in JavaScript, veuillez élaborer, je suis curieux!
Karl Morrison
L'une des raisons est que toutes les fonctions Constructor intégrées en JavaScript créées comme cette fonction Number () {[code natif]} et que vous ne devriez pas être confondu avec les fonctions intégrées, également le référencement plus tard dans ce cas est plus sûr et vous finissez un code plus net mais sans utiliser de levage ...
Alireza
8

Ce ne sont que deux façons possibles de déclarer des fonctions et, dans le second, vous pouvez utiliser la fonction avant la déclaration.

Tao
la source
7

new Function()peut être utilisé pour passer le corps de la fonction dans une chaîne. Et donc cela peut être utilisé pour créer des fonctions dynamiques. Passer également le script sans exécuter le script.

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

secondFunction()
SuperNova
la source
Bien que cela soit bon et vrai, comment cela se rapporte-t-il exactement à la question posée?
Jack Giffin