Cette syntaxe JavaScript, je n'ai pas vu jusqu'à maintenant, qu'est-ce que ça fait vraiment?

Aujourd'hui, j'ai vu une syntaxe JavaScript (lorsqu'on invoquait une fonction) qui ne me connaissait pas. C'était comme:

def('Person') ({ init: function(name) {this.name=name;} ,speak: function(text) {alert(text || 'Hi, my name is ' + this.name);} }); 

, et

 def('Ninja') << Person ({ kick: function() {this.speak('I kick u!');} }); 

1: Que se passe-t-il avec l'objet entre parenthèses dans le premier exemple? Il est géré par la fonction def , mais je ne comprends pas ce qui se passe ici (voir la fonction def ci-dessous). Où l'objet va-t-il?

2: À propos de la même chose encore, mais une utilisation de l'opérateur << que je n'ai jamais vu (je pense!). Tout ça c'est à propos de quoi?

Le code provient de http://gist.github.com/474994 , où Joe Dalton a fait une petite chose de JavaScript-OO-inheritance (il est apparemment une fourchette de travail de quelqu'un d'autre, mais tout à fait réécrit, comme il le semble). Peut-être que vous voulez vérifier les choses référencées par la fonction def , que je vous donne ici:

 function def(klassName, context) { context || (context = global); // Create class on given context (defaults to global object) var Klass = context[klassName] = function Klass() { // Called as a constructor if (this != context) { // Allow the init method to return a different class/object return this.init && this.init.apply(this, arguments); } // Called as a method // defer setup of superclass and plugins deferred._super = Klass; deferred._plugins = arguments[0] || { }; }; // Add static helper method Klass.addPlugins = addPlugins; // Called as function when not // inheriting from a superclass deferred = function(plugins) { return Klass.addPlugins(plugins); }; // valueOf is called to set up // inheritance from a superclass deferred.valueOf = function() { var Superclass = deferred._super; if (!Superclass) return Klass; Subclass.prototype = Superclass.prototype; Klass.prototype = new Subclass; Klass.superclass = Superclass; Klass.prototype.constructor = Klass; return Klass.addPlugins(deferred._plugins); }; return deferred; } 

1: L'appel def('Person') renvoie une fonction, appelée avec l'objet comme paramètre. C'est le même principe que:

 function x() { return function(y) { alert(y); } } x()('Hello world!'); 

2: L'opérateur << est l'opérateur gauche. Il déplace une valeur entière d'un nombre spécifique de bits vers la gauche. Je n'ai trouvé aucune référence pour aucune autre utilisation, et il n'y a pas de surcharge d'opérateur en version Javascript, donc je ne peux pas avoir le sens de l'utiliser sur une fonction. Jusqu'à présent, ça me paraît une faute de frappe.

Modifier:

Comme Tim l'a expliqué, l'opérateur de changement de vitesse sert à induire un appel à la méthode valueOf . Cela fonctionne comme une surcharge de tous les opérateurs, en reprenant le but original et en faisant quelque chose de complètement différent.

Wow, il était assez compliqué pour que mon cerveau minuscule comprenne, mais je me sens bien mieux maintenant en sachant exactement comment ça fonctionne 🙂 Merci à @Tim pour avoir souligné le truc valueOf() .

Le cas général de création d'une "class" utilisant:

 def ("ClassName") ({ init: function() { .. }, foo: function() { .. } }); 

Est trivial, car le premier appel à def renvoie une fonction qui accepte un objet et copie les propriétés de l'objet passé dans le prototype de ClassName .

Le cas le plus intéressant d'utiliser << à la sous-classe repose sur l'ordre d'évaluation de l'expression, ainsi que la tentative de coercition d'un objet à une valeur par l'appel implicite à valueOf() . L'astuce sous-jacente est essentiellement une variable partagée qui enregistre la super classe et les propriétés qui lui sont appliquées. L'expression,

 def("ClassName") << ParentClass({ .. }) 

Sera évalué comme suit:

  1. def("ClassName") est appelé et crée un objet global ClassName et renvoie sa fonction de constructeur. Appelons cet objet retourné – initializeMeLater .
  2. ParentClass(..) est appelé qui stocke la référence à ParentClass et l'objet / propriétés passés dans une variable partagée.
  3. initializeMeLater.valueOf() est appelé, qui obtient la référence à la classe parent et les propriétés de cette variable partagée et configure les prototypes.
  4. valueOf est appelé sur la valeur de retour de l'étape 2 qui est inutile et n'a aucun effet, car nous avons déjà configuré la relation superclasse à l'étape 3.

Le code essaie d'imiter la syntaxe Ruby pour créer des sous-classes qui se passent comme suit:

 class Child < Parent def someMethod ... end end