54 votes

Pourquoi le guide de style Airbnb indique-t-il qu'il est déconseillé de recourir à l'inférence de nom de fonction?

 // bad
class Listing extends React.Component {
  render() {
    return <div>{this.props.hello}</div>;
  }
}

// bad (relying on function name inference is discouraged)
const Listing = ({ hello }) => (
  <div>{hello}</div>
);

// good
function Listing({ hello }) {
  return <div>{hello}</div>;
}
 

C’est tiré du guide de style d’Airbnb. Quelqu'un peut-il s'il vous plaît expliquer pourquoi "s'appuyer sur l'inférence de nom de fonction est découragée"? Est-ce juste une préoccupation de style?

32voto

Brad Colthurst Points 1663

Je pense que cela pourrait aussi avoir quelque chose à voir avec le comportement inattendu de ce que vous pourriez courir à partir implicitement donner un lexicale nom à quoi vous pouvez vous attendre à être une fonction anonyme.

Disons, par exemple, quelqu'un a compris la flèche de la fonction:

(x) => x+2;

Pour avoir la fonction ordinaire équivalent:

function(x) {
  return x+2;
}

Il serait assez facile de s'attendre à ce code:

let foo = (x) => x+2;

Pour ensuite être l'équivalent de:

let foo = function(x) {
  return x+2;
}

Où la fonction reste anonyme et serait incapable de référencement de lui-même pour faire des choses comme la récursivité.

Donc, si ensuite, dans notre douce ignorance, nous avons eu quelque chose comme ce qui se passe:

let foo = (x) => (x<2) ? foo(2) : "foo(1)? I should be a reference error";
console.log(foo(1));

Il serait exécuté avec succès parce que la fonction de toute évidence n'était pas anonyme:

let foo = function foo(x) {
  return (x<2) ? foo(2) : "foo(1)? I should be a reference error";
}  

Cela pourrait être aggravée par le fait que, dans d'autres situations où Babel ajoute implicitement un nom pour les fonctions anonymes (qui je pense est en fait un peu un effet secondaire de l'appui implicite des noms de fonction en premier lieu, bien que j'ai peut être tort sur ce point), ils gérer correctement tout les cas limites et lancer des erreurs de référence où vous pouvez vous attendre.

Par exemple:

let foo = {
  bar: function() {}
} 

// Will surprisingly transpile to..

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


// But doing something like:

var foo = {
  bar: function(x) {
    return (x<2) ? bar(2) : 'Whats happening!?';
  }
}

console.log(foo.bar(1));

// Will correctly cause a ReferenceError: bar is not defined

Vous pouvez cocher " afficher compilé sur cette rapide DÉMONSTRATION pour voir comment Babel est en fait transpiling que pour maintenir le comportement d'une fonction anonyme.


En bref, être explicite avec ce que vous faites est généralement une bonne idée parce que vous savez exactement à quoi s'attendre de votre code. En décourageant l'utilisation de la fonction implicite de nommage est probablement un choix stylistiques à l'appui de cette, tout en restant concis et simple.

Et probablement de levage. Mais bon, le côté amusant voyage.

27voto

Ashley Coolman Points 356

EDIT #2: Trouvé AirBnbs la raison dans leur style Javascript guide

N'oubliez pas de nom de l'expression des fonctions anonymes, peuvent rendre plus difficile à localiser le problème une Erreur de la pile d'appel (Discussion)

Réponse originale à cette question ci-dessous

MDN a une bonne course vers le bas sur la façon dont le nom de la fonction d'inférence œuvres, dont deux mises en garde:

Observations

Il est non-standard, <function>.name d'inférence du comportement dans les deux scénarios suivants:

  1. lors de l'utilisation de script interprètes

L'interpréteur de script permettra de définir un nom de la fonction, bien que si une fonction n'a pas une propriété appelée du nom de...

  1. lors de l'utilisation de js outillage

Être prudent lors de l'utilisation de la Fonction.le nom et le code source de transformations telles que celles menées par le JavaScript compresseurs (minifiers) ou obfuscators

....

Dans la version non compressée du programme s'exécute dans le truthy-branche et les journaux " foo " est une instance de 'Foo', tandis que dans la version compressée il se comporte différemment et fonctionne dans l'autre branche. Par conséquent, si vous comptez sur la Fonction.nom comme dans l'exemple ci-dessus, assurez-vous que votre build pipeline ne change pas les noms de fonction ou de ne pas assumer une fonction pour avoir un nom particulier.

Quel est le nom de la fonction d'inférence?

L' name propriété renvoie le nom d'une fonction, ou (avant ES6 implémentations) une chaîne vide pour les fonctions anonymes

function doSomething() {}

console.log(doSomething.name); // logs "doSomething"

Fonctions créées avec la syntaxe d'une Fonction nouvelle(...) ou tout simplement de la Fonction(...) ont leur nom de la propriété est définie sur une chaîne vide. Dans les exemples suivants, les fonctions anonymes sont créés, le nom renvoie une chaîne vide

var f = function() {};
var object = {
  someMethod: function() {}
};

console.log(f.name == ''); // true
console.log(object.someMethod.name == ''); // also true

Les navigateurs qui implémentent ES6 fonctions peuvent déduire le nom d'une fonction anonyme à partir de sa position syntaxique. Par exemple:

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

Avis

Personnellement, je préfère (flèche) fonctions attribuées à une variable pour trois raisons essentielles:

Tout d'abord, je n'ai pas jamais utiliser function.name

Deuxièmement, le mélange portée lexicale des fonctions nommées avec l'affectation se sent un peu en vrac:

// This...
function Blah() {
   //...
}
Blah.propTypes = {
 thing: PropTypes.string
}
// ...is the same as...
Blah.propTypes = {
 thing: PropTypes.string
}
function Blah() {
   //...
}

// ALTERNATIVELY, here lexical-order is enforced
const Blah = () => {
   //...
}
Blah.propTypes = {
    thing: PropTypes.string
}

Et troisièmement, toutes choses étant égales par ailleurs, je préfère flèche fonctions:

  • communiquer au lecteur qu'il n'y a pas d' this, n arguments etc
  • regarde mieux (à mon humble avis)
  • les performances (la dernière fois que j'ai regardé, flèche fonctions ont été légèrement plus rapide)

EDIT: instantanés de la Mémoire

J'ai été l'écoute d'un Podcast et invité a parlé d'une situation étaient, il avait à faire avec les limitations de l'utilisation de la flèche fonctions avec le profilage de la mémoire, j'ai été dans l' exacte même situation avant.

Actuellement, instantanés de la mémoire ne sera pas inclure un nom de variable - de sorte que vous pourriez trouver vous-même la conversion de flèche de fonctions de fonctions nommées juste à brancher le profileur de mémoire. Mon expérience a été assez simple, et je suis toujours heureux avec flèche fonctions.

En Plus je ne l'ai utilisé instantanés de la mémoire une fois, je me sens à l'aise renoncer à certains "instrumention" pour (subjective) de clarté par défaut.

4voto

JordanHendrix Points 7878

Ceci est dû au fait:

 const Listing = ({ hello }) => (
  <div>{hello}</div>
);
 

a un nom inféré de Listing, bien qu'il semble que vous le nommiez, vous ne l'êtes pas:

Exemple

 // we know the first three ways already...

let func1 = function () {};
console.log(func1.name); // func1

const func2 = function () {};
console.log(func2.name); // func2

var func3 = function () {};
console.log(func3.name); // func3
 

Et ça?

 const bar = function baz() {
    console.log(bar.name); // baz
    console.log(baz.name); // baz
};

function qux() {
  console.log(qux.name); // qux
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X