Quelle est l'utilisation de la construction: function F() { if (!(this instanceof F)) { return new F() }; ... }
function F() { if (!(this instanceof F)) { return new F() }; ... }
?
J'ai trouvé cela dans un pty.js
pour Node. Voici le code original:
function Terminal(file, args, opt) { if (!(this instanceof Terminal)) { return new Terminal(file, args, opt); } var self = this , env , cwd , name , cols , rows , term; -------------------SKIP----------------------------------- Terminal.total++; this.socket.on('close', function() { Terminal.total--; self._close(); self.emit('exit', null); }); env = null; }
Cela signifie que si la fonction était appelée sans le new
opérateur, elle retournera automatiquement une nouvelle instance.
Par exemple, si vous n'aviez pas cette garantie, et avez-vous …
var t = Terminal();
… alors, this
tout en exécutant Terminal()
pointerait vers la window
(ou votre objet global, fancy non-browser guy / gal), certainement pas ce que vous voulez.
En déterminant que c'est en fait une instance de Terminal
, nous pouvons continuer. Sinon, la sauvegarde renvoie un nouvel objet.
Ensuite, nous pouvons simplement utiliser les deux formes …
var t = Terminal(); // Will be same as `new Terminal()`
C'est juste pour s'assurer que cela fonctionnera même si F
est appelé sans new
.
Lorsque vous appelez F
avec new
, dans cette fonction, this
s'agit de la nouvelle instance.
Ensuite, si this
n'est pas une instance de F
( !(this instanceof F)
), cela signifie que F
n'a pas été appelé à l'aide de new
. Dans ce cas, F
s'appelle lui-même, maintenant avec new
.
En plus des grandes explications de ce fil, il est intéressant de voir ce qui se passe sous le capot. La spécification ECMAScript (où Javascript est basé) définit un objet global . Ceci est implémenté différemment dans différents environnements d'exécution. Dans votre navigateur typique, c'est l'objet window
dans Node.js c'est l'objet root
. Chaque fonction définie "in the wild" (non attachée à un objet créé par l'utilisateur) deviendra une propriété de l'objet global. Dans Node.js, vous pouvez essayer:
> function Test() {}; > root.Test [Function: Test]
Maintenant, this
variable indique l'objet dans lequel la fonction est membre . Donc, dans l'exemple ci-dessus:
> function Test() { ... console.log(this === root); ... }; > Test() true
Même chose pour votre Terminal
fonction. Si vous l'exécutez, this
indiquera l'objet global qui n'est évidemment pas une instance de Terminal
!
Lorsque vous appelez une fonction à l'aide du new
opérateur, un objet est renvoyé qui aura accès à une propriété appelée constructor
qui rappellera cette fonction. C'est quelque chose qui équivaut à:
> var instance = {}; > instance.constructor = Terminal; > instance.constructor();
Donc, lorsque le conditionnel échoue et que la fonction Terminal fonctionne à travers la new Terminal()
, this
indiquera une instance nouvellement créée qui est de type Terminal!
Si vous souhaitez obtenir plus d'informations techniques, l' instance
n'a pas de propriété constructor
elle-même. Il est plutôt lié (via la chaîne prototype *), à un objet privé ** (créé par l'exécution) qui possède une propriété constructor
indiquant la fonction Terminal. Cet objet privé est rappelé par la fonction à travers un prototype
propriété. D.Crockford présente ceci en pseudocode comme suit:
Terminal.prototype = {constructor: Terminal};
Encore une fois, ce n'est que lorsque vous appelez la fonction avec une new
.
* Si une propriété n'est pas trouvée, l'objet recherchera l'objet désigné par la propriété __proto__
.
** (imaginez quelque chose comme un objet appelé _Terminal
que vous ne pouvez pas accéder par nom)