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


568

Dans une autre question , un utilisateur a souligné que le newmot - 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 newmot - 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 newmot - clé dans son code ( Crockford on JavaScript - Act III: Function the Ultimate - 50:23 minutes ).

Est-il «mauvais» d'utiliser le newmot-clé? Quels sont les avantages et les inconvénients de son utilisation?


90
Il n'est PAS «mauvais» d'utiliser le nouveau mot-clé. Mais si vous l'oubliez, vous appellerez le constructeur d'objet en tant que fonction régulière. Si votre constructeur ne vérifie pas son contexte d'exécution, il ne remarquera pas que «ceci» pointe vers un objet différent (généralement 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 «ceci» est une instance de votre objet dans la fonction objet, vous n'aurez jamais ce problème.
Kristian B

5
Je ne comprends pas ça. D'une part, Doug décourage l'utilisation de new. Mais quand vous regardez la bibliothèque YUI. Vous devez utiliser newpartout. Tels que var myDataSource = new Y.DataSource.IO({source:"./myScript.php"}); .
aditya_gaur

2
@aditya_gaur C'est parce que si vous avez besoin d'une initialisation d'un objet, vous devrez pirater une initméthode si vous utilisez l' Object.createapproche et l'appeler après. Beaucoup plus facile à utiliser, newqui fait les deux, définit la chaîne de prototypes et appelle du code d'initialisation.
Juan Mendes

67
Je ne pense pas que cela aurait dû être fermé. Oui, il est susceptible d'inspirer du venin anti-ventilateur Crockford, mais nous parlons de conseils populaires pour éviter essentiellement une fonctionnalité linguistique majeure ici. Le mécanisme qui fait que chaque objet JQuery ne pèse presque rien (en ce qui concerne la mémoire) implique l'utilisation du «nouveau» mot clé. Préférez les méthodes d'usine pour invoquer constamment de nouvelles, mais ne réduisez pas considérablement vos options architecturales et votre potentiel de performance en utilisant uniquement des littéraux d'objet. Ils ont leur place et les constructeurs ont leur place. Ce sont des conseils basiques et moche.
Erik Reppen

2
TLDR: L'utilisation newn'est pas dangereuse. Omettre newest dangereux et donc mauvais . Mais dans ES5, vous pouvez utiliser le mode strict , qui vous protège contre ce danger et bien d'autres.
jkdev

Réponses:


603

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 newmot - clé présente plusieurs avantages par rapport à la construction de chaque objet à partir de zéro:

  1. Héritage du prototype . Bien que souvent considérée avec un mélange de suspicion et de dérision par ceux habitués aux langages OO basés sur les classes, la technique d'héritage native de JavaScript est un moyen simple et étonnamment efficace de réutilisation du code. Et le nouveau mot-clé est le moyen canonique (et uniquement multiplateforme 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 pourrais simplement écrire une fonction de création qui attribue manuellement chaque méthode à chaque nouvel objet ... Ou, je pourrais les affecter à la fonction de création prototypeet utiliser newpour é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, newa 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:

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 ne newpas 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:

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

(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 withest particulièrement instructif pour ceux d'entre nous qui ont initialement rejeté cette fonctionnalité tant décriée comme un gadget).


96
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.
du

5
Si vous êtes préoccupé par les performances - et avez réellement des raisons de l'être - alors ne faites pas du tout la vérification. N'oubliez pas d'utiliser newou 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 ...
Shog9

65
Utiliser arguments.calleepour vérifier si vous avez été appelé newn'est peut-être pas si bon, car il arguments.calleen'est pas disponible en mode strict. Mieux vaut utiliser le nom de la fonction.
Sean McMillan

69
Si j'épelle mal un identifiant, mon code se brise. Ne dois-je pas utiliser d'identifiants? Ne pas utiliser newcar vous pouvez oublier de l'écrire dans votre code est tout aussi ridicule que mon exemple.
Thomas Eding

16
Si vous activez le mode strict, si vous oubliez d'utiliser de nouveau , vous aurez une exception lorsque vous essayez d'utiliser ceci: yuiblog.com/blog/2010/12/14/strict-mode-is-coming-to-town C'est plus simple que d'ajouter une instance de check à chaque constructeur.
stephenbez

182

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:

Je ne laisse jamais les boîtiers de commutation passer au cas suivant. Une fois, j'ai trouvé un bogue dans mon code provoqué par une chute involontaire immédiatement après avoir fait un discours vigoureux sur la raison pour laquelle la chute était parfois utile. (page 97, ISBN 978-0-596-51774-8)

À propos de ++ et -

Les opérateurs ++ (incrémenter) et - (décrémenter) sont connus pour contribuer au mauvais code en encourageant une ruse excessive. Ils viennent juste après une architecture défectueuse pour activer les virus et autres menaces de sécurité. (page 122)

À propos de nouveau:

Si vous oubliez d'inclure le nouveau préfixe lors de l'appel d'une fonction constructeur, cela ne sera pas lié au nouvel objet. Malheureusement, cela sera lié à l'objet global, donc au lieu d'augmenter votre nouvel objet, vous encombrerez les variables globales. C'est vraiment mauvais. Il n'y a aucun avertissement de compilation et aucun avertissement d'exécution. (page 49)

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, thisn'est plus lié à l'objet global mais à undefined.


3
Je suis complètement d'accord. La solution: documentez toujours comment les utilisateurs doivent instancier vos objets. Utilisez un exemple et les utilisateurs couperont / colleront probablement. Il existe des constructions / fonctionnalités dans chaque langue qui peuvent être utilisées à mauvais escient entraînant un comportement inhabituel / inattendu. Cela ne les rend pas nocifs.
nicerobot

45
Il existe une convention pour toujours démarrer les constructeurs avec une lettre majuscule et toutes les autres fonctions avec une lettre minuscule.
du

61
Je viens de me rendre compte que Crockford ne considère pas TOUT EN TANT QUE dangereux ... Je ne sais pas combien de fois j'ai créé une boucle infinitive parce que j'ai oublié d'incrémenter une variable ...
du

5
Il en va de même pour ++, -. Ils expriment exactement ce que j'entends dans le langage le plus clair possible. Je les aime! certains passages peuvent être clairs pour certains, mais je suis fatigué à ce sujet. Je les utilise quand ils sont clairement plus clairs («cuse le jeu de mots, je n'ai pas pu résister).
PEZ

30
Ma réponse à Crockford: La programmation est difficile, allons faire du shopping. Sheesh!
Jason Jackson

91

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 newsur 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: -

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

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.

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
Ouais, je pensais juste la même chose à propos de la coloration syntaxique.
BobbyShaftoe

4
Une fois, j'ai oublié de taper le mot «fonction». Le mot doit être évité à tout prix. Une autre fois, je n'ai pas utilisé d'accolades dans une instruction if / then sur plusieurs lignes. Alors maintenant, je n'utilise pas d'accolades et j'écris simplement des conditions sur une ligne.
Hal50000

"C'est clairement faux" . Pourquoi? Pour mes classes (qui le font tout simplement if (! this instanceof MyClass) return new MyClass()), je préfère en fait la newsyntaxe -less. Pourquoi? Parce que les fonctions sont plus génériques que les fonctions constructeurs . Laisser de côté newpermet de changer facilement une fonction constructeur en fonction régulière ... Ou l'inverse. L'ajout newrend le code plus spécifique qu'il ne devrait l'être. Et donc moins flexible. Comparez avec Java où il est recommandé d'accepter Listau lieu de ArrayListafin que l'appelant puisse choisir l'implémentation.
Stijn de Witt

41

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 avec var bar = new foo();je sais que la barre est un objet.


3
D'accord, et je crois que le modèle d'usine devrait suivre une convention de dénomination comme makeFoo ()
pluckyglen

3
+1 - la présence de «nouveau» donne une déclaration d'intention plus claire.
belugabob

4
Cette réponse est un peu bizarre, quand presque tout dans JS est un objet. Pourquoi avez-vous besoin de savoir avec certitude qu'une fonction est un objet alors que toutes les fonctions sont des objets?
Joshua Ramirez

@JoshuaRamirez Le point n'est pas cela typeof new foo() == "object". C'est cela qui newrenvoie une instance de foo, et vous savez que vous pouvez appeler foo.bar()et foo.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 mot new)
Juan Mendes

1
@JuanMendes Hmm ... Votre message m'a fait croire que vous aimiez le nouveau en raison de son mot clé explicite dans votre base de code. Je peux creuser ça. C'est pourquoi j'utilise un modèle de module. J'aurai une fonction appelée createFoo ou NewFoo ou MakeFoo, n'a pas d'importance tant qu'elle est explicite. À l'intérieur, je déclare des variables qui sont utilisées comme fermetures à l'intérieur d'un littéral d'objet renvoyé par la fonction. Cet objet littéral finit par être votre objet, et la fonction n'était qu'une fonction de construction.
Joshua Ramirez

39

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.


3
+1 pour le lien Pooh Coding - maintenant j'ai besoin de trouver des excuses pour
intégrer

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

1
Je ne sais pas si vous verrez jamais ce commentaire, mais ce lien de codage Pooh est mort.
Calvin le

Merci pour l'information. Nous avons migré robowiki.net vers un nouveau wiki la semaine dernière et l'ancien contenu est inaccessible pour le moment. Je vais me dépêcher de faire fonctionner ces anciens liens.
PEZ

24

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 newet 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:

/**
 * 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);

6
éviter arguments.calleec'est génial!
Gregg Lind

2
surrogateConstructordevrait être surrogateCtor(ou vice versa).
David Conrad

J'ai conservé une collection d'utilitaires similaires inspirés de Crockford, et j'ai constaté que j'avais toujours besoin de courir pour trouver les implémentations lorsque je commençais un nouveau projet. Et cela enveloppe une partie si fondamentale de la programmation: l'instanciation d'objets. Tout ce travail, juste pour activer le code d'instanciation aléatoire? J'apprécie l'ingéniosité de cet emballage, honnêtement, mais il semble simplement engendrer un codage imprudent.
Joe Coder

1
@joecoder J'ai mentionné que c'était à des fins didactiques uniquement, je ne souscris pas à ce style de codage paranoïaque. Cependant, si j'écrivais une bibliothèque de classe, alors oui, j'ajouterais cette fonctionnalité d'une manière transparente pour les appelants
Juan Mendes

22

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

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

Alternativement, vous pouvez donc 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 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.


6
Non. Avec "new foo ()", certaines propriétés sont définies sur l'objet renvoyé, comme le constructeur.
du

34
Donc, pour que ce soit clair: vous ne devriez pas utiliser «nouveau» parce que vous pourriez l'oublier? Tu rigole c'est ça?
Bombe

16
@Bombe: dans d'autres langues, oublier "nouveau" entraînerait une erreur. En Javascript, il continue de camionnage. Vous pouvez oublier et ne jamais réaliser. Et simplement regarder du code erroné ne sera pas du tout évident ce qui ne va pas.
Kent Fredric

3
@Greg: Je ne vois pas comment la première technique permet d'utiliser des chaînes de prototypes - les littéraux d'objets sont excellents, mais abandonner par crainte les performances et autres avantages fournis par les prototypes semble un peu idiot.
Shog9

5
@Bombe - Vous devriez utiliser "nouveau" parce que vous (et quiconque utilise votre code) ne vous tromperez jamais? Tu rigole c'est ça?
Greg Dean

20

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.


16

Cas 1: newn'est pas requis et doit ê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: newest requis, sinon vous obtiendrez une erreur

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

5
Il convient de noter que dans le cas 1, appeler le constructeur en tant que fonction n'a de sens que si vous envisagez une conversion de type (et ne savez pas si l'objet coque a une méthode de conversion, telle que toString()). Dans tous les autres cas, utilisez des littéraux. Non String('asd') , mais simplement 'asd', et non Number(12) , mais simplement 12.
PointedEars

1
@PointedEars Une exception à cette règle serait 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);
yyny

@YoYoYonnY Ma déclaration a été faite dans le contexte du cas 1 de la réponse, qui se réfère à l'utilisation de newavec des constructeurs pour les types d'objets correspondant aux types primitifs . Le littéral que vous proposez n'est pas équivalent à l' Arrayappel (try 0 in …), et le reste est une erreur de syntaxe :) Sinon, vous avez raison, même s'il convient de noter également que cela Array(5)peut être ambigu si vous considérez des implémentations non conformes (et donc un émulé Array.prototype.fill(…) ).
PointedEars

12

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' newopérateur:

Argument contre new

  1. Les fonctions conçues pour être instanciées en tant qu'objets utilisant l' newopé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.
  2. Enfin, écrire function Func(), puis appeler Func.prototype et ajouter des éléments pour que vous puissiez appeler new 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

  1. L'utilisation de l' newopérateur avec l'affectation prototypique est rapide.
  2. Ce truc sur l'exécution accidentelle du code d'une fonction constructeur dans l'espace de noms global peut facilement être évité si vous incluez toujours un peu de code dans vos fonctions constructeur pour vérifier si elles sont appelées correctement et, dans les cas où elles ne le sont pas , en traitant l'appel de manière appropriée comme vous le souhaitez.

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.


Une mise à jour sur les arguments contre: # 1 peut être atténuée en utilisant le '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.
ninMonkey

9

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;ou var bar = baz();que baz ne soit pas une méthode de création d'objet semble beaucoup plus dangereuse.


8

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

Object.create=function(proto){
  var F = function(){};
  F.prototype = proto;
  var instance = new F();
  return instance;
};

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.


7
Pour être honnête, je ne suis pas folle de cette technique - elle n'ajoute rien de nouveau, et comme votre réponse l'illustre, elle peut même finir par être une béquille. À mon humble avis, comprendre les chaînes de prototypes et l'instanciation d'objets est crucial pour comprendre JavaScript ... Mais si cela vous met mal à l'aise de les utiliser directement, alors utiliser une fonction d'aide pour prendre soin de certains détails est très bien, tant que vous vous souvenez de ce que vous êtes Faire. FWIW: une variation (un peu plus utile) à ce sujet fait partie de l'ECMAScript 5e éd. std, et déjà disponible dans certains navigateurs - vous devez donc faire attention de ne pas le redéfinir aveuglément!
Shog9

BTW: Je ne sais pas pourquoi vous avez fait ce CW, mais si vous voulez le
republier

2
Inutilement difficile à comprendre? var c = new Car()est la même chose que de fairevar c = Object.create(Car.prototype); Car.call(c)
Juan Mendes
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.