Dans une autre question , un utilisateur a souligné que le new
mot - clé était dangereux à utiliser et a proposé une solution à la création d'objets qui ne l'utilisait pas new
. Je ne pensais pas que c'était vrai, principalement parce que j'avais utilisé Prototype, Scriptaculous et d'autres excellentes bibliothèques JavaScript, et tout le monde utilisait le new
mot - clé.
Malgré cela, hier, je regardais la conférence de Douglas Crockford au théâtre YUI et il a dit exactement la même chose, qu'il n'utilisait plus le new
mot - clé dans son code ( Crockford on JavaScript - Act III: Function the Ultimate - 50:23 minutes ).
Est-il «mauvais» d'utiliser le new
mot-clé? Quels sont les avantages et les inconvénients de son utilisation?
javascript
Pablo Fernandez
la source
la source
new
. Mais quand vous regardez la bibliothèque YUI. Vous devez utilisernew
partout. Tels quevar myDataSource = new Y.DataSource.IO({source:"./myScript.php"});
.init
méthode si vous utilisez l'Object.create
approche et l'appeler après. Beaucoup plus facile à utiliser,new
qui fait les deux, définit la chaîne de prototypes et appelle du code d'initialisation.new
n'est pas dangereuse. Omettrenew
est dangereux et donc mauvais . Mais dans ES5, vous pouvez utiliser le mode strict , qui vous protège contre ce danger et bien d'autres.Réponses:
Crockford a fait beaucoup pour vulgariser les bonnes techniques JavaScript. Sa position d'opinion sur les éléments clés du langage a suscité de nombreuses discussions utiles. Cela dit, il y a beaucoup trop de gens qui prennent chaque proclamation de «mauvais» ou de «nuisible» comme évangile, refusant de regarder au-delà de l'opinion d'un seul homme. Cela peut parfois être un peu frustrant.
L'utilisation de la fonctionnalité fournie par le
new
mot - clé présente plusieurs avantages par rapport à la construction de chaque objet à partir de zéro:prototype
et utilisernew
pour éradiquer de nouveaux objets. Non seulement cela est plus rapide (aucun code n'est 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 des machines plus lentes (ou en particulier des interprètes JS plus lents), lorsque de nombreux objets sont créés, cela peut signifier des économies importantes de temps et de mémoire.Et oui,
new
a un inconvénient crucial, bien décrit par d'autres réponses: si vous oubliez de l'utiliser, votre code se cassera sans avertissement. Heureusement, cet inconvénient est facilement atténué - ajoutez simplement un peu de code à la fonction elle-même:Maintenant, vous pouvez avoir les avantages de ne
new
pas avoir à vous soucier des problèmes causés par une mauvaise utilisation accidentelle. Vous pouvez même ajouter une assertion à la vérification si la pensée de travailler en silence vous dérange. Ou, comme certains l'ont commenté, utilisez la vérification pour introduire une exception d'exécution:(Notez que cet extrait de code peut éviter de coder en dur le nom de la fonction constructeur, car contrairement à l'exemple précédent, il n'a pas besoin d'instancier réellement l'objet - par conséquent, il peut être copié dans chaque fonction cible sans modification.)
John Resig explique en détail cette technique dans son article sur l' instanciation "Classe" simple , ainsi que l'inclusion d'un moyen d'intégrer ce comportement dans vos "classes" par défaut. Vaut vraiment la peine d'être lu ... tout comme son livre à venir, Secrets of the JavaScript Ninja , qui trouve de l'or caché dans cela et dans de nombreuses autres fonctionnalités "nuisibles" du langage JavaScript (le chapitre sur
with
est particulièrement instructif pour ceux d'entre nous qui ont initialement rejeté cette fonctionnalité tant décriée comme un gadget).la source
new
ou utilisez une fonction wrapper pour vous en souvenir. Je soupçonne que si vous êtes au point où cela compte, vous avez déjà épuisé d'autres optimisations telles que la mémorisation, de sorte que vos appels de création seront localisés de toute façon ...arguments.callee
pour vérifier si vous avez été appelénew
n'est peut-être pas si bon, car ilarguments.callee
n'est pas disponible en mode strict. Mieux vaut utiliser le nom de la fonction.new
car vous pouvez oublier de l'écrire dans votre code est tout aussi ridicule que mon exemple.Je viens de lire certaines 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:
À propos de la chute du commutateur:
À propos de ++ et -
À propos de nouveau:
Il y en a plus, mais j'espère que vous aurez compris.
Ma réponse à votre question: non, ce n'est pas dangereux. mais si vous oubliez de l'utiliser quand vous le devriez, vous pourriez avoir des problèmes. Si vous évoluez dans un bon environnement, vous le remarquerez.
Mise à jour
Environ un an après la rédaction de cette réponse, la 5e édition d'ECMAScript a été publiée, avec prise en charge du mode strict . En mode strict,
this
n'est plus lié à l'objet global mais àundefined
.la source
Javascript étant un langage dynamique, il existe de nombreuses façons de gâcher là où une autre langue pourrait vous arrêter.
Éviter une fonctionnalité de langage fondamentale, par exemple
new
sur la base que vous pourriez gâcher, c'est un peu comme retirer vos nouvelles chaussures brillantes avant de traverser un champ de mines au cas où vous pourriez obtenir vos chaussures boueuses.J'utilise une convention où les noms de fonctions commencent par une lettre minuscule et les «fonctions» qui sont en fait des définitions de classe commencent par une lettre majuscule. Le résultat est un indice visuel vraiment assez convaincant que la «syntaxe» est fausse: -
En plus de ces bonnes habitudes de dénomination, cela aide. Après toutes les fonctions font des choses et donc il devrait y avoir un verbe dans son nom alors que les classes représentent des objets et sont des noms et des adjectifs sans verbe.
Il est intéressant de voir comment la coloration syntaxique de SO a interprété le code ci-dessus.
la source
if (! this instanceof MyClass) return new MyClass()
), je préfère en fait lanew
syntaxe -less. Pourquoi? Parce que les fonctions sont plus génériques que les fonctions constructeurs . Laisser de côténew
permet de changer facilement une fonction constructeur en fonction régulière ... Ou l'inverse. L'ajoutnew
rend le code plus spécifique qu'il ne devrait l'être. Et donc moins flexible. Comparez avec Java où il est recommandé d'accepterList
au lieu deArrayList
afin que l'appelant puisse choisir l'implémentation.Je suis novice en Javascript, alors je ne suis peut-être pas trop expérimenté pour fournir un bon point de vue à ce sujet. Pourtant, je veux partager mon point de vue sur cette "nouvelle" chose.
Je viens du monde C # où l'utilisation du mot-clé "nouveau" est si naturelle que c'est le modèle de conception d'usine qui me semble étrange.
Quand je code pour la première fois en Javascript, je ne me rends pas compte qu'il y a le "nouveau" mot-clé et le code comme celui du modèle YUI et il ne me faut pas longtemps pour tomber en catastrophe. Je perds la trace de ce qu'une ligne particulière est censée faire lorsque je regarde le code que j'ai écrit. Plus chaotique est que mon esprit ne peut pas vraiment transiter entre les limites des instances d'objets lorsque je "fais tourner à sec" le code.
Ensuite, j'ai trouvé le "nouveau" mot clé qui pour moi, ça "séparait" les choses. Avec le nouveau mot-clé, cela crée des choses. Sans le nouveau mot-clé, je sais que je ne le confondrai pas avec la création de choses à moins que la fonction que j'invoque ne m'en donne des indices solides.
Par exemple, avec
var bar=foo();
je n'ai aucune idée de ce que pourrait être la barre ... Est-ce une valeur de retour ou est-ce un objet nouvellement créé? Mais avecvar bar = new foo();
je sais que la barre est un objet.la source
typeof new foo() == "object"
. C'est cela quinew
renvoie une instance defoo
, et vous savez que vous pouvez appelerfoo.bar()
etfoo.bang()
. Cependant cela peut facilement être atténués à l'aide de @return de jsdoc Non pas que je préconise pour le code de procédure ( en évitant le motnew
)Un autre cas de nouveauté est ce que j'appelle Pooh Coding . Winnie l'Ourson suit son ventre. Je dis aller avec la langue que vous utilisez, pas contre elle.
Il y a de fortes chances que les responsables de la langue optimisent la langue pour les idiomes qu'ils essaient d'encourager. S'ils mettent un nouveau mot clé dans la langue, ils pensent probablement qu'il est logique d'être clair lors de la création d'une nouvelle instance.
Le code écrit suivant les intentions du langage augmentera en efficacité avec chaque version. Et le code évitant les constructions clés du langage en souffrira avec le temps.
EDIT: Et cela va bien au-delà de la performance. Je ne peux pas compter les fois où j'ai entendu (ou dit) "pourquoi diable ont-ils fait ça ?" lors de la recherche d'un code étrange. Il s'avère souvent qu'au moment 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 ridiculiser votre code dans quelques années.
la source
J'ai écrit un article sur la façon d'atténuer le problème d'appeler un constructeur sans le nouveau mot clé.
C'est principalement didactique, mais il montre comment vous pouvez créer des constructeurs qui fonctionnent avec ou sans
new
et ne vous oblige pas à ajouter du code passe-this
partout à tester dans chaque constructeur.http://js-bits.blogspot.com/2010/08/constructors-without-using-new.html
Voici l'essentiel de la technique:
Voici comment l'utiliser:
la source
arguments.callee
c'est génial!surrogateConstructor
devrait êtresurrogateCtor
(ou vice versa).La raison de ne pas utiliser le nouveau mot-clé est simple:
En ne l'utilisant pas du tout, vous évitez l'écueil qui vient de l'omettre accidentellement. Le modèle de construction utilisé par YUI est un exemple de la façon dont vous pouvez éviter complètement le nouveau mot clé "
Alternativement, vous pouvez donc ceci:
Mais ce faisant, vous courez le risque que quelqu'un oublie d'utiliser le nouveau mot-clé et que cet opérateur soit entièrement fubar. AFAIK il n'y a aucun avantage à faire cela (à part que vous y êtes habitué).
À la fin de la journée: il s'agit d'être défensif. Pouvez-vous utiliser la nouvelle déclaration? Oui. Est-ce que cela rend votre code plus dangereux? Oui.
Si vous avez déjà écrit C ++, cela revient à définir des pointeurs sur NULL après les avoir supprimés.
la source
Je pense que "nouveau" ajoute de la clarté au code. Et la clarté vaut tout. C'est bon de savoir qu'il y a des pièges, mais les éviter en évitant la clarté ne me semble pas être la solution.
la source
Cas 1:
new
n'est pas requis et doit être évitéCas 2:
new
est requis, sinon vous obtiendrez une erreurla source
toString()
). Dans tous les autres cas, utilisez des littéraux. NonString('asd')
, mais simplement'asd'
, et nonNumber(12)
, mais simplement12
.Array
:Array(5).fill(0)
est évidemment plus lisible que[undefined, undefined, undefined, undefined, undefined].fill(0)
et(var arr = []).length = 5; arr.fill(0);
new
avec des constructeurs pour les types d'objets correspondant aux types primitifs . Le littéral que vous proposez n'est pas équivalent à l'Array
appel (try0 in …
), et le reste est une erreur de syntaxe :) Sinon, vous avez raison, même s'il convient de noter également que celaArray(5)
peut être ambigu si vous considérez des implémentations non conformes (et donc un émuléArray.prototype.fill(…)
).Voici le résumé le plus bref que j'ai pu faire des deux arguments les plus forts pour et contre l'utilisation de l'
new
opérateur:Argument contre
new
new
opérateur peuvent avoir des effets désastreux si elles sont invoquées de manière incorrecte en tant que fonctions normales. Le code d'une fonction dans un tel cas sera exécuté dans la portée où la fonction est appelée, plutôt que dans la portée d'un objet local comme prévu. Cela peut entraîner le remplacement des variables et propriétés globales avec des conséquences désastreuses.function Func()
, puis appelerFunc.prototype
et ajouter des éléments pour que vous puissiez appelernew Func()
pour construire votre objet semble moche à certains programmeurs, qui préfèrent utiliser un autre style d'héritage d'objet pour des raisons architecturales et stylistiques.Pour en savoir plus sur cet argument, consultez le grand livre concis de Douglas Crockford Javascript: The Good Parts. En fait, vérifiez-le de toute façon.
Argument en faveur de
new
new
opérateur avec l'affectation prototypique est rapide.Voir le post de John Resig pour une explication simple de cette technique, et pour une explication généralement plus approfondie du modèle d'héritage qu'il préconise.
la source
'use strict';
mode (ou la méthode dans votre lien) # 2 A du sucre synatique dans ES6 , cependant le comportement est le même qu'avant.Je suis d'accord avec Pez et certains ici.
Il me semble évident que "nouveau" est la création d'objets auto-descriptifs, où le modèle YUI décrit par Greg Dean est complètement obscurci .
La possibilité que quelqu'un écrive
var bar = foo;
ouvar bar = baz();
que baz ne soit pas une méthode de création d'objet semble beaucoup plus dangereuse.la source
Je pense que le nouveau est mauvais, non pas parce que si vous oubliez de l'utiliser par erreur, cela pourrait causer des problèmes, mais parce qu'il gâche la chaîne d'héritage, rendant la langue plus difficile à comprendre.
JavaScript est orienté objet basé sur un prototype. Par conséquent, chaque objet DOIT être créé à partir d'un autre objet comme celui-ci
var newObj=Object.create(oldObj)
. Ici, oldObj est appelé le prototype de newObj (d'où «basé sur un prototype»). Cela implique que si une propriété n'est pas trouvée dans newObj, elle sera recherchée dans oldObj . newObj par défaut sera donc un objet vide mais en raison de sa chaîne prototype, il semble avoir toutes les valeurs de oldObj .D'un autre côté, si vous le faites
var newObj=new oldObj()
, le prototype de newObj est oldObj.prototype , ce qui est inutilement difficile à comprendre.L'astuce consiste à utiliser
C'est à l'intérieur de cette fonction et seulement ici que new doit être utilisé. Après cela, utilisez simplement la méthode Object.create () . La méthode résout le problème du prototype.
la source
var c = new Car()
est la même chose que de fairevar c = Object.create(Car.prototype); Car.call(c)