596 votes

Le mot-clé "nouveau" de JavaScript est-il considéré comme nuisible ?

Dans un autre question un utilisateur a fait remarquer que le new était dangereux à utiliser et proposait une solution pour la création d'objets qui n'utilisait pas le mot-clé new . Je ne croyais pas que c'était vrai, surtout parce que j'ai utilisé Prototype, Scriptaculous et d'autres excellentes bibliothèques JavaScript, et que chacune d'entre elles utilisait la méthode de l'interface utilisateur. new mot-clé.

Malgré cela, hier, j'ai regardé la conférence de Douglas Crockford au YUI theater et il a dit exactement la même chose, à savoir qu'il n'utilisait pas l'option new plus de mot-clé dans son code ( Crockford on JavaScript - Acte III : La fonction ultime - 50:23 minutes ).

Est-il "mauvais" d'utiliser le new mot-clé ? Quels sont les avantages et les inconvénients de son utilisation ?

97 votes

Il n'est PAS "mauvais" d'utiliser le nouveau mot-clé. Mais si vous l'oubliez, vous appellerez le constructeur d'objet comme une fonction normale. Si votre constructeur ne vérifie pas son contexte d'exécution, il ne remarquera pas que "this" pointe vers un objet différent (habituellement l'objet global) au lieu de la nouvelle instance. Par conséquent, votre constructeur ajoutera des propriétés et des méthodes à l'objet global (fenêtre). Si vous vérifiez toujours que 'this' est une instance de votre objet dans la fonction objet, alors vous n'aurez jamais ce problème.

5 votes

Je ne comprends pas. D'un côté Doug décourage l'utilisation de new . Mais quand vous regardez la bibliothèque YUI. Vous devez utiliser new partout. Par exemple var myDataSource = new Y.DataSource.IO({source:"./myScript.php"}); .

2 votes

@aditya_gaur C'est parce que si vous avez besoin de l'initialisation d'un objet, vous devez bidouiller un init si vous utilisez la méthode Object.create et de l'appeler après. Il est beaucoup plus facile d'utiliser new qui fait les deux, définit la chaîne de prototypes et appelle du code d'initialisation.

627voto

Shog9 Points 82052

Crockford a beaucoup fait pour populariser les bonnes techniques JavaScript. Ses prises de position sur les éléments clés du langage ont suscité de nombreuses discussions utiles. Cela dit, il y a beaucoup trop de gens qui prennent chaque proclamation de "mauvais" ou "nuisible" comme parole d'évangile, refusant de regarder au-delà de l'opinion d'un homme. C'est parfois un peu frustrant.

L'utilisation de la fonctionnalité fournie par le new présente plusieurs avantages par rapport à la construction de chaque objet à partir de zéro :

  1. Héritage des prototypes . Bien qu'elle soit souvent considérée avec un mélange de suspicion et de dérision par ceux qui sont habitués aux langages OO basés sur des classes, la technique d'héritage natif de JavaScript est un moyen simple et étonnamment efficace de réutiliser le code. Et le nouveau mot-clé est le moyen canonique (et le seul disponible sur toutes les plates-formes) de l'utiliser.
  2. Performance. Il s'agit d'un effet secondaire du point 1 : si je souhaite ajouter 10 méthodes à chaque objet que je crée, je dois pourrait juste écrire une fonction de création qui assigne manuellement chaque méthode à chaque nouvel objet... Ou bien, je pourrais les assigner à la fonction de création. prototype et utiliser new pour supprimer les nouveaux objets. Non seulement cela est plus rapide (pas de code nécessaire pour chaque méthode du prototype), mais cela évite de gonfler chaque objet avec des propriétés distinctes pour chaque méthode. Sur les machines plus lentes (ou surtout sur les interpréteurs JS plus lents), lorsque de nombreux objets sont créés, cela peut représenter un gain de temps et de mémoire considérable.

Et oui, new a un inconvénient crucial, habilement décrit par d'autres réponses : si vous oubliez de l'utiliser, votre code sera cassé sans avertissement. Heureusement, cet inconvénient est facilement atténué - il suffit d'ajouter un peu de code à la fonction elle-même :

function foo()
{
   // if user accidentally omits the new keyword, this will 
   // silently correct the problem...
   if ( !(this instanceof foo) )
      return new foo();

   // constructor logic follows...
}

Vous pouvez désormais bénéficier des avantages suivants new sans avoir à se soucier des problèmes causés par une mauvaise utilisation accidentelle. Vous pouvez même ajouter une assertion à la vérification si l'idée d'un code cassé fonctionnant en silence vous dérange. Ou, comme un peu de commenté, utilisez le contrôle pour introduire une exception d'exécution :

if ( !(this instanceof arguments.callee) ) 
   throw new Error("Constructor called as a function");

(Notez que ce snippet est capable d'éviter le codage en dur du nom de la fonction constructeur, car contrairement à l'exemple précédent, il n'a pas besoin d'instancier réellement l'objet - il peut donc être copié dans chaque fonction cible sans modification).

John Resig explique cette technique en détail dans son livre intitulé Instanciation de "classe" simple ainsi qu'un moyen d'intégrer ce comportement par défaut dans vos "classes". Cela vaut vraiment la peine de le lire... tout comme son prochain livre, Les secrets du ninja JavaScript qui trouve de l'or caché dans cette caractéristique et dans beaucoup d'autres caractéristiques "nuisibles" du langage JavaScript (la page chapitre sur with est particulièrement instructif pour ceux d'entre nous qui ont d'abord considéré cette fonction très décriée comme un gadget).

103 votes

If ( !(this instanceof arguments.callee)) throw Error("Constructor called as a function");// Plus générique, ne nécessite pas la connaissance du nom du constructeur, oblige l'utilisateur à corriger le code.

0 votes

@some : Oui ! Si tu es capable de tester et de corriger le code du client, alors ce serait un excellent choix.

0 votes

@Shog9, merci - excellent commentaire (j'ai appris quelque chose de nouveau) !

190voto

some Points 18965

Je viens de lire quelques parties de son livre de Crockfords "Javascript : The Good Parts". J'ai l'impression qu'il considère tout ce qui l'a mordu comme nuisible :

L'échange est en cours :

Je ne permets jamais que les cas d'échange tombent de passer au cas suivant. J'ai trouvé une fois un bug dans mon code causé par une par un passage involontaire, immédiatement après avoir fait un discours vigoureux sur les raisons pour lesquelles le fall through était parfois utile. (page 97, ISBN 978-0-596-51774-8)

A propos de ++ et --

Les opérateurs ++ (incrémentation) et -- (décrémentation) sont connus pour contribuer à un mauvais code en encourageant en encourageant une astuce excessive. Ils sont en deuxième position après les architectures défectueuses pour les virus et autres problèmes de sécurité. sécurité. (page 122)

A propos du neuf :

Si vous oubliez d'inclure le nouveau lors de l'appel d'un constructeur alors ce ne sera pas lié au nouvel objet. Triste, ce sera lié à l'objet global, donc au lieu d'augmenter votre nouvel objet, vous allez détruire les variables globales. C'est vraiment mauvais. Il y a n'y a pas d'avertissement de compilation, et il n'y a pas de d'exécution. (page 49)

Il y en a d'autres, mais j'espère que vous voyez le tableau.

Ma réponse à votre question : Non, ce n'est pas dangereux. mais si vous oubliez de l'utiliser au bon moment, vous risquez d'avoir des problèmes. Si vous développez dans un bon environnement, vous le remarquez.

Mise à jour

Environ un an après la rédaction de cette réponse, la 5e édition d'ECMAScript a été publiée, avec la prise en charge des éléments suivants mode strict . En mode strict, this n'est plus lié à l'objet global mais à l'objet undefined .

4 votes

Je suis tout à fait d'accord. La solution : Toujours documenter comment les utilisateurs doivent instancier vos objets. Utilisez un exemple et les utilisateurs feront probablement un copier/coller. Il y a des constructions/fonctionnalités dans chaque langage qui peuvent être mal utilisées et donner lieu à un comportement inhabituel/imprévu. Cela ne les rend pas nocifs pour autant.

48 votes

Il existe une convention selon laquelle les constructeurs commencent toujours par une majuscule et toutes les autres fonctions par une minuscule.

64 votes

Je viens de réaliser que Crockford ne considère pas WHILE comme nuisible... Je ne sais pas combien de fois j'ai créé une boucle infinitive parce que j'avais oublié d'incrémenter une variable...

93voto

AnthonyWJones Points 122520

Javascript étant un langage dynamique, il y a des millions de façons de se tromper là où un autre langage vous arrêterait.

Éviter une caractéristique fondamentale de la langue telle que new au cas où vous feriez une erreur, c'est un peu comme si vous enleviez vos chaussures neuves avant de traverser un champ de mines, au cas où vos chaussures seraient boueuses.

J'utilise une convention selon laquelle les noms de fonctions commencent par une lettre minuscule et les "fonctions" qui sont en fait des définitions de classes commencent par une lettre majuscule. Le résultat est un indice visuel très convaincant qui indique que la "syntaxe" est incorrecte.

var o = MyClass();  // this is clearly wrong.

En outre, de bonnes habitudes en matière de dénomination sont utiles. Après tout, les fonctions font des choses et doivent donc comporter un verbe dans leur nom, tandis que les classes représentent des objets et sont des noms et des adjectifs sans verbe.

var o = chair() // Executing chair is daft.
var o = createChair() // makes sense.

Il est intéressant de voir comment la coloration syntaxique de SO a interprété le code ci-dessus.

8 votes

Oui, je pensais justement la même chose à propos de la coloration de la syntaxe.

5 votes

Une fois, j'ai oublié de taper le mot "fonction". Ce mot doit être évité à tout prix. Une autre fois, je n'ai pas utilisé les accolades dans une instruction if/then de plusieurs lignes. Maintenant, je n'utilise plus d'accolades et j'écris des conditionnels d'une ligne.

1 votes

"C'est clairement faux" . Pourquoi ? Pour mes cours (qui font simplement if (! this instanceof MyClass) return new MyClass() ) En fait, je préfère le new -sans syntaxe. Pourquoi ? Parce que fonctions sont plus génériques que fonctions de construction . En laissant de côté new permet de transformer facilement une fonction constructeur en une fonction normale... Ou l'inverse. L'ajout de new rend le code plus spécifique qu'il ne doit l'être. Et donc moins flexible. Comparez avec Java où il est recommandé d'accepter List au lieu de ArrayList afin que l'appelant puisse choisir l'implémentation.

41voto

Conrad Points 460

Je suis novice en Javascript et je ne suis peut-être pas assez expérimenté pour donner un bon point de vue sur ce sujet. Pourtant, je veux partager mon point de vue sur cette "nouvelle" chose.

Je viens du monde du C# où l'utilisation du mot clé "new" est si naturelle que c'est le modèle de conception "factory" qui me semble bizarre.

Lorsque je code pour la première fois en Javascript, je ne réalise pas qu'il existe le mot-clé "new" et un code comme celui du modèle YUI et il ne me faut pas longtemps pour courir au désastre. Je perds la trace de ce qu'une ligne particulière est censée faire lorsque je regarde en arrière le code que j'ai écrit. Ce qui est encore plus chaotique, c'est que mon esprit ne peut pas vraiment transiter entre les limites des instances d'objets lorsque je "sèche" le code.

Ensuite, j'ai trouvé le "nouveau" mot-clé qui, pour moi, "sépare" les choses. Avec le nouveau mot-clé, il crée des choses. Sans le mot-clé new, je sais que je ne le confondrai pas avec la création de choses, sauf si la fonction que j'invoque m'en donne de forts indices.

Par exemple, avec var bar=foo(); Je n'ai aucun indice sur ce que la barre pourrait être.... S'agit-il d'une valeur de retour ou d'un objet nouvellement créé ? Mais avec var bar = new foo(); Je suis sûr que le bar est un objet.

4 votes

Je suis d'accord, et je pense que le modèle de fabrique devrait suivre une convention de dénomination comme makeFoo()

3 votes

+1 - la présence de "nouveau" donne une déclaration d'intention plus claire.

4 votes

Cette réponse est un peu bizarre, alors que presque tout en JS est un objet. Pourquoi avoir besoin de savoir avec certitude qu'une fonction est un objet alors que toutes les fonctions sont des objets ?

40voto

PEZ Points 9662

Un autre cas pour nouveau est ce que j'appelle Codage de l'ourson . Winnie l'ourson suit son ventre. Je dis : vas-y avec la langue que vous utilisez, et non contre il.

Il y a de fortes chances que les mainteneurs du langage optimisent le langage pour les idiomes qu'ils essaient d'encourager. S'ils introduisent un nouveau mot-clé dans le langage, ils pensent probablement qu'il est judicieux d'être clair lors de la création d'une nouvelle instance.

Le code écrit en respectant les intentions du langage gagnera en efficacité à chaque version. Et le code qui évite les constructions clés du langage souffrira avec le temps.

EDIT : Et cela va bien au-delà des performances. Je ne compte plus le nombre de fois où j'ai entendu (ou dit) "pourquoi diable ont-ils fait que ?" lorsqu'on trouve un code qui semble étrange. Il s'avère souvent qu'à l'époque où le code a été écrit, il y avait une "bonne" raison à cela. Suivre le Tao de la langue est votre meilleure assurance pour ne pas voir votre code ridiculisé dans quelques années.

3 votes

+1 pour le lien Pooh Coding - maintenant je dois trouver des excuses pour intégrer cela dans mes conversations...

0 votes

LOL ! J'ai des années d'expérience dans ce domaine particulier et je peux vous assurer que vous ne rencontrerez aucune difficulté. On m'appelle souvent Pooh sur robowiki.net. =)

1 votes

Je ne sais pas si tu verras ce commentaire, mais le lien vers Pooh Coding est mort.

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