Question Le «nouveau» mot clé de JavaScript est-il considéré comme nuisible? [fermé]


En autre question, un utilisateur a souligné que new mot-clé était dangereux à utiliser et a proposé une solution à la création d'objets qui n'a pas utilisé 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 chacun d'entre eux a utilisé le new mot-clé.

Malgré cela, hier je regardais le discours de Douglas Crockford au théâtre YUI et il a dit exactement la même chose, qu'il n'a pas utilisé le new mot-clé dans son code (Crockford sur JavaScript - Acte III: Fonction de l'ultime - 50:23 minutes).

Est-ce «mauvais» d'utiliser le new mot-clé? Quels sont les avantages et les inconvénients de l'utiliser?


544
2017-12-20 15:20


origine


Réponses:


Crockford a beaucoup fait pour populariser les bonnes techniques JavaScript. Sa position sur les principaux éléments de la langue a suscité de nombreuses discussions utiles. Cela dit, il y a beaucoup trop de gens qui considèrent chaque proclamation de «mauvais» ou de «nuisible» comme évangile, refusant de regarder au-delà de l'opinion d'un homme. Cela peut parfois être un peu frustrant.

Utilisation de la fonctionnalité fournie par le new mot-clé a plusieurs avantages par rapport à la construction de chaque objet à partir de zéro:

  1. Héritage de prototype. Bien que souvent considéré avec un mélange de suspicion et de dérision par ceux qui sont habitués aux langages OO basés sur les classes, la technique de l'héritage natif de JavaScript est un moyen simple et étonnamment efficace de réutilisation du code. Et le nouveau mot-clé est le moyen canonique (et seulement multiplate-forme disponible) de l'utiliser.
  2. Performance. Ceci est un effet secondaire de # 1: si je veux ajouter 10 méthodes à chaque objet que je crée, je pourrait il suffit d'écrire une fonction de création qui affecte manuellement chaque méthode à chaque nouvel objet ... Ou, je pourrais les affecter à la fonction de création prototype et utilise new pour éradiquer de nouveaux objets. Non seulement cela est-il plus rapide (aucun code n'est nécessaire pour chaque méthode sur le prototype), mais cela évite de gonfler chaque objet avec des propriétés séparées pour chaque méthode. Sur les machines plus lentes (ou en particulier, les interprètes JS plus lents) lorsque de nombreux objets sont créés, cela peut entraîner des économies significatives de temps et de mémoire.

Et oui, new a un inconvénient crucial, habilement 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é - 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...
}

Maintenant, vous pouvez avoir les avantages de new sans 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 code brisé fonctionne silencieusement vous dérange. Ou, comme certains commenté, utilisez la vérification pour introduire une exception d'exécution:

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

(Notez que cet extrait est capable d'é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 va dans les détails sur cette technique dans son Simple "Classe" Instanciation post, ainsi que d'inclure un moyen de construire ce comportement dans vos "classes" par défaut. Vaut vraiment le coup d'être lu ... comme son livre à venir, Les secrets du JavaScript Ninja, qui trouve l'or caché dans ce et beaucoup d'autres "nuisibles" caractéristiques du langage JavaScript (le chapitre sur with est particulièrement éclairant pour ceux d'entre nous qui ont initialement rejeté cette fonctionnalité tant décriée comme un gadget).


584
2017-12-20 17:17



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

À propos de l'interrupteur tomber à travers:

Je n'autorise jamais les boîtiers de commutation à tomber   à travers au cas suivant. J'ai déjà trouvé   un bug dans mon code causé par un   tomber involontairement à travers immédiatement   après avoir fait un discours vigoureux   à propos de pourquoi tomber à travers était parfois   utile. (page 97, ISBN   978-0-596-51774-8)

À propos de ++ et -

Le ++ (incrément) et - (décrément)   les opérateurs ont été connus pour   contribuer à un mauvais code en encourageant   trickiness exessive. Ils sont seconds   seulement à l'architecture défectueuse   activer les virus et autres mesures de sécurité   menaces. (page 122)

A propos de nouveau:

Si vous oubliez d'inclure le Nouveau   préfixe lors de l'appel d'un constructeur   fonction, puis ce ne sera pas   lié au nouvel objet. Malheureusement, ce   sera lié à l'objet global, donc   au lieu d'augmenter votre nouvel objet,   vous allez bousculer global   variables C'est vraiment mauvais. Là   est pas d'avertissement de compilation, et il n'y a pas   avertissement d'exécution. (page 49)

Il y en a plus, mais j'espère que vous aurez l'image.

Ma réponse à ta 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 vous développez dans un bon environnement, vous le remarquerez.

Mettre à jour

Environ un an après que cette réponse a été écrite, la 5ème édition d'ECMAScript a été publiée, avec le soutien de mode strict. En mode strict, this n'est plus lié à l'objet global mais à undefined.


174
2017-12-20 15:43



Javascript étant une langue dynamique, il y a des tas de façons de gâcher où une autre langue vous arrêtera.

Éviter une fonctionnalité de langage fondamentale telle que new sur la base que vous pourriez gâcher est un peu comme enlever vos nouvelles chaussures brillantes avant de marcher dans un champ de mines juste 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 très convaincant que la 'syntaxe' est fausse: -

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

En plus de cela, de bonnes habitudes de nommage aident. 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.

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

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


91
2017-12-20 17:10



Je suis novice à Javascript alors peut-être que je ne suis 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 de C # où l'utilisation du mot-clé "nouveau" est si naturelle que c'est le modèle de conception d'usine qui me semble bizarre.

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 dans le désastre. Je perds la trace de ce qu'une ligne particulière est supposée faire en regardant le code que j'ai écrit. Ce qui est plus chaotique, c'est que mon esprit ne peut pas vraiment passer d'une frontière d'instance d'objet à l'autre quand 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 nouveau mot-clé, je sais que je ne vais pas le confondre avec la création de choses à moins que la fonction que j'appelle me donne de fortes indications à ce sujet.

Par exemple, avec var bar=foo(); Je n'ai aucune idée de ce que la barre pourrait éventuellement être .... Est-ce une valeur de retour ou est-ce un objet nouvellement créé? Mais avec var bar = new foo(); Je sais à coup sûr que la barre est un objet.


43
2017-12-22 09:22



Un autre cas pour nouveau est ce que j'appelle Codage de l'ourson. Winnie l'ourson suit son ventre. Je dis aller avec la langue que vous utilisez, pas contre il.

Les chances sont que les mainteneurs 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 de la langue augmentera en efficacité avec chaque version. Et le code qui évite les constructions clés de la langue va souffrir avec le temps.

EDIT: Et cela va bien au-delà des performances. Je ne peux pas compter les fois où j'ai entendu (ou dit) "pourquoi diable ont-ils fait cette"Lorsque vous trouvez un code étrange, il s'avère souvent qu'au moment où le code a été écrit, il y avait une" bonne "raison: le Tao de la langue est votre meilleure assurance pour ne pas avoir ridiculisé votre code quelques années. à présent.


39
2017-12-20 18:25



J'ai écrit un post sur la façon d'atténuer le problème d'appeler un constructeur sans le nouveau mot-clé.
C'est surtout didactique, mais cela montre comment vous pouvez créer des constructeurs qui fonctionnent avec ou sans new et ne vous oblige pas à ajouter code standard tester this dans chaque constructeur.

http://js-bits.blogspot.com/2010/08/constructors-without-using-new.html

Voici l'essentiel de la technique:

/**
 * Wraps the passed in constructor so it works with
 * or without the new keyword
 * @param {Function} realCtor The constructor function.
 *    Note that this is going to be wrapped
 *    and should not be used directly 
 */
function ctor(realCtor){
  // This is going to be the actual constructor
  return function wrapperCtor(){
    var obj; // object that will be created
    if (this instanceof wrapperCtor) {
      // Called with new
      obj = this;
    } else {
      // Called without new. Create an empty object of the
      // correct type without running that constructor
      surrogateCtor.prototype = wrapperCtor.prototype;
      obj = new surrogateCtor();
    }
    // Call the real constructor function
    realCtor.apply(obj, arguments);
    return obj;
  }

  function surrogateCtor() {}
}

Voici comment l'utiliser:

// Create our point constructor
Point = ctor(function(x,y){
  this.x = x;
  this.y = y;
});

// This is good
var pt = new Point(20,30);
// This is OK also
var pt2 = Point(20,30);

24
2018-06-20 22:52



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 avec l'omettre accidentellement. Le modèle de construction que YUI utilise, est un exemple de la façon dont vous pouvez éviter le nouveau mot-clé "

var foo = function () {
    var pub= { };
    return pub;
}
var bar = foo();

Alternativement vous pourriez ainsi ceci:

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

Mais ce faisant, vous courez le risque que quelqu'un oublie d'utiliser le Nouveau mot-clé, et le ce l'opérateur étant tout fubar. AFAIK il n'y a aucun avantage à faire ceci (autre que vous êtes habitué).

À la fin de la journée: Il s'agit d'être sur la défensive.  Pouvez-vous utiliser la nouvelle déclaration? Oui. Cela rend-il 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.


22
2017-12-20 15:42



Je pense que "nouveau" ajoute de la clarté au code. Et la clarté vaut tout. Bon à savoir il y a des pièges, mais les éviter en évitant la clarté ne me semble pas être le chemin.


20
2017-12-20 16:12



Cas 1: new n'est pas requis et devrait être évité

var str = new String('asd');  // type: object
var str = String('asd');      // type: string

var num = new Number(12);     // type: object
var num = Number(12);         // type: number

Cas 2: new est requis, sinon vous aurez une erreur

new Date().getFullYear();     // correct, returns the current year, i.e. 2010
Date().getFullYear();         // invalid, returns an error

15
2017-11-13 17:04



Voici le résumé le plus bref que j'ai pu faire des deux arguments les plus forts pour et contre l'utilisation du new opérateur:

Argument contre new

  1. Fonctions conçues pour être instancié comme des objets en utilisant le new l'opérateur peut avoir désastreux effets si elles sont incorrectes invoqué comme des fonctions normales. UNE le code de la fonction dans un tel cas être exécuté dans le champ d'application où la fonction est appelée, au lieu de la portée d'un objet local comme prévu. Cela peut causer des problèmes mondiaux variables et propriétés à obtenir écrasé avec désastreux conséquences.
  2. Enfin, l'écriture function Func(), puis en appelant Func.prototype et en ajoutant des choses pour que vous pouvoir appeler new Func() construire votre objet semble laid à certains programmeurs, qui préfèrent utiliser un autre style d'héritage d'objet pour architectural et stylistique les raisons.

Pour en savoir plus sur cet argument, consultez le livre de Douglas Crockford, grand et concis, intitulé Javascript: The Good Parts. En fait, vérifiez-le quand même.

Argument en faveur de new

  1. En utilisant le new opérateur avec l'affectation prototypique est rapide.
  2. Ce truc sur accidentellement exécuter une fonction de constructeur code dans l'espace de noms global peut facilement être évité si vous toujours inclure un peu de code dans votre fonctions du constructeur pour vérifier voir si on les appelle correctement, et, dans les cas où ils ne le sont pas, ils s'occupent de l'appel de manière appropriée comme souhaité.

Voir Le message de John Resig pour une explication simple de cette technique, et pour une explication généralement plus profonde du modèle d'héritage qu'il préconise.


12
2017-12-28 23:47



Je suis d'accord avec Pez et certains ici.

Il me semble évident que "nouveau" est la création d'objet auto descriptif, où le modèle YUI Greg Dean décrit est complètement obscurci.

La possibilité que quelqu'un puisse écrire var bar = foo; ou var bar = baz(); où baz n'est pas une méthode de création d'objet semble loin plus dangereux.


9
2017-12-20 17:10