11
votes

Quelle différence existe-t-il dans JavaScript entre une fonction de constructeur et une fonction d'objet de retour qui est invoquée comme constructeur?

Je sais que ce n'est pas la manière recommandée de le faire, mais si je déclare les fonctions suivantes, puis les appeler comme constructeurs, quelle sera la différence (le cas échéant) entre les objets résultants?

function Something() {
    this.foo = "bar";
}

function something2() {
    var that = {};
    that.foo = "bar";
    return that;
}

var x = new Something();
var y = new something2();
var z = something2();


1 commentaires

Soyez un peu méfiant de M. Crockford. Bien qu'il ait beaucoup de bonnes choses à dire, il a des opinions qui ne sont pas d'accord.


4 Réponses :


2
votes

Dans le second cas, l'objet retourné n'hérite rien du constructeur, il y a donc peu de point de l'utiliser comme tel.

> var x = new Something();
> var y = new something2();
> var z = something2();


0 commentaires

15
votes

bref: xxx pré>

lié, si vous étendez votre exemple pour utiliser la propriété prototype p> xxx pré>

Vous constaterez que le prototype n'est pas hérité dans ce dernier cas: p> xxx pré>


La réponse réelle est que vous tapez dans des machines sous-jacentes entièrement différentes. Appeler avec nouveau code> invoque le [[CONSTRUCTION]] Mécanisme, qui consiste à définir la propriété [[prototype]] selon la propriété .pototype code> du constructeur. p>

mais une chose amusante se passe dans les étapes 8--10 de la [construction ]] ALGORITHM: Après avoir configuré un nouvel objet vide, puis la fixation de son [[prototype]], il fait un [[[appel]] au constructeur actuel, à l'aide de ce nouvel objet vide-prototype comme code>. Ensuite, à l'étape 9, s'il s'avère que ce constructeur a renvoyé quelque chose -, il lance ce qui est protégé par prototypalement, passé- cet objet code> qu'il a passé tout ce temps à installer!

Remarque: Vous pouvez accéder à un objet [[prototype]] (qui est différent du .pototype de constructeur code>) avec objet.geprotypeof code>: p >

Object.getPrototypeOf(new Something()) === Something.prototype // steps 5 & 6
Object.getPrototypeOf(new something2()) === Object.prototype // default
  • Non, ne capitalise pas quelque chose2 code>, puisqu'il s'agit d'une fonction d'usine et non d'un constructeur. Si quelque chose est capitalisé, il est censé avoir une sémantique du constructeur, par ex. Nouvelle instance A () d'un code>. Li>
  • Si vous êtes inquiet du danger d'encombrer l'espace de noms global, vous devez commencer à utiliser mode strict , en mettant "Utiliser strict"; code> en haut de vos fichiers. L'un des nombreux nettoyages de mode strict est que ceci code> par défaut sur non défini code>, pas l'objet global, donc par ex. Appeler un constructeur sans Nouveau code> entraînera des erreurs le moment où le constructeur tente de joindre des propriétés à non défini code>. li>.
  • Fonctions d'usine (AKA Le "modèle de fermeture") sont en général un substitut raisonnable pour les constructeurs et les classes, à condition que vous n'ayez pas utilisé l'héritage; (b) ne pas construire trop d'instances de cet objet. Ce dernier est parce que, dans le motif de fermeture, vous attachez une nouvelle instance de chaque méthode à chaque objet nouvellement créé, ce qui n'est pas génial pour l'utilisation de la mémoire. Le plus grand gain, imo, du modèle de fermeture est la possibilité d'utiliser "Variables" privées " ( qui sont un bonne chose , et ne laissez personne vous dire Sinon: p). li> ul> p>


5 commentaires

Le «nouveau» est également facultatif (ou en effet non nécessaire) sur la deuxième méthode, mais vise les choses lorsque vous êtes laissé dans la première (cette fenêtre ===)


@ Matt-Vous pouvez défendre contre celui-ci un peu de l'intérieur du constructeur en voyant si ceci est l'objet global et la procédure en conséquence.


@Matt, @robg --- ou, viens de mettre "utiliser strict"; en haut de votre fichier! Alors ceci sera non défini .


@Dominic au sommet de la fonction suffit - mais nous devrons attendre Jscript pour suivre la hausse. En général, le mode strict ES5 n'est pas une caractéristique sûre encore, même dans Non-Jscript.


Pourquoi attendre Jscript? Il vous aidera à attraper vos erreurs dans le développement, où vous testez probablement plus que c'est à savoir <= 8. Et cela ne fait rien de mal dans la production.



1
votes

Invoquant une fonction en tant que constructeur (c'est-à-dire avec le nouveau mot-clé ) exécute les étapes suivantes:

  1. créer un nouvel objet
  2. Définissez le prototype de cet objet sur l'objet dans le prototype Propriété de la fonction
  3. Exécutez la fonction constructeur dans le contexte de cet objet (c'est-à-dire Ceci est le nouvel objet)
  4. retourner cet objet (si le constructeur n'a pas de retour instruction)

    Donc, votre deuxième solution renverra simplement un objet simple avec une propriété "FOO". Mais aucun Y ni z est instance de quelque chose2 et n'hérite pas de ce prototype. Il existe des fonctions comme ça, oui, mais ils ne doivent pas être appelés constructeurs (pas de nommage majuscule, aucune invocation avec nouveau ). Ils appartiennent au modèle d'usine.

    Si vous voulez un constructeur qui peut être exécuté sans neuf, utilisez ce code: xxx


0 commentaires

1
votes

Je dirais que la chose la plus importante serait le prototype des objets retournés.

var that = new Object();


0 commentaires