Questa syntax JavaScript che non ho visto fino ad ora, che cosa fa veramente?

Oggi ho visto una syntax JavaScript (quando si richiama una funzione) che non mi è familiare. Era come:

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

, e

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

1: Cosa succede con l’object tra parentesi nel primo esempio? È gestito dalla funzione def qualche modo, ma non capisco cosa sta succedendo qui (vedi la funzione def basso). Dove va l’object?

2: Ancora la stessa cosa, ma un uso dell’operatore << che non ho mai visto (credo!). Di cosa si tratta?

Il codice è tratto da http://gist.github.com/474994 , dove Joe Dalton ha realizzato una piccola cosa di ereditarietà OO-JavaScript (è apparentemente un fork del lavoro di qualcun altro, ma completamente riscritto, come sembra). Forse vuoi verificarlo là fuori per le cose a cui fa riferimento la funzione def , che ti do qui:

 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: La chiamata def('Person') restituisce una funzione, che viene chiamata con l’object come parametro. È lo stesso principio di:

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

2: L’operatore << è l'operatore di spostamento a sinistra. Sposta un valore intero di un numero specifico di bit a sinistra. Non ho trovato alcun riferimento per nessun altro uso per questo, e non c'è sovraccarico dell'operatore in Javascript, quindi non posso avere alcun senso a usarlo su una funzione. Finora mi sembra un errore di battitura.

Modificare:

Come ha spiegato Tim, l'operatore di spostamento è semplicemente usato per indurre una chiamata al metodo valueOf . Funziona come un sovraccarico di tutti gli operatori, riprendendo lo scopo originale e facendo qualcosa di completamente diverso.

Wow, è stato abbastanza complicato da capire il mio piccolo cervello, ma ora mi sento molto meglio sapendo esattamente come funziona 🙂 Grazie a @Tim per aver sottolineato il trucco valueOf() .

Il caso generale di creare una "class" usando:

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

è banale, poiché la prima chiamata a def restituisce una funzione che accetta un object e copia le proprietà dell’object passato nel prototipo di ClassName .

Il caso più interessante dell’uso di << per sottoclass si basa sull'ordine di valutazione dell'espressione, così come sul tentativo di coercizione di qualsiasi object su un valore mediante la chiamata implicita a valueOf() . Il trucco sottostante è fondamentalmente una variabile condivisa che registra la super class e le proprietà da applicare ad essa. L'espressione,

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

sarà valutato come segue:

  1. def("ClassName") viene chiamato e crea un object globale ClassName e restituisce la sua funzione di costruzione. Chiamiamo questo object restituito - initializeMeLater .
  2. ParentClass(..) chiamato ParentClass(..) che memorizza il riferimento a ParentClass e il passato in object / proprietà in una variabile condivisa.
  3. initializeMeLater.valueOf() viene chiamato, che ottiene il riferimento alla class genitore e le proprietà da quella variabile condivisa e imposta i prototipi.
  4. valueOf viene chiamato sul valore di ritorno del punto 2, che è inutile e non ha alcun effetto, poiché abbiamo già impostato la relazione della superclass nel passaggio 3.

Il codice sta cercando di emulare la syntax di Ruby per creare sottoclassi che vanno come:

 class Child < Parent def someMethod ... end end