2012-01-29 6 views
7

Riferimento: http://ejohn.org/blog/simple-class-instantiation/John Resig di classe e "use strict"

// makeClass - By John Resig (MIT Licensed) 
function makeClass(){ 
    return function(args){ 
    if (this instanceof arguments.callee) { 
     if (typeof this.init == "function") 
     this.init.apply(this, args.callee ? args : arguments); 
    } else 
     return new arguments.callee(arguments); 
    }; 
} 

mi chiedevo, se ce ne sono ECMAScript 5 modo compatibile per implementare la stessa funzionalità. Il problema è che l'accesso a arguments.callee è deprecato in modalità rigorosa.

risposta

4

Come ho capito, arguments.callee non è deprecato in modalità rigorosa, nel qual caso è possibile continuare a utilizzarlo; piuttosto, è stato rimosso e il tentativo di utilizzo genererà (o dovrebbe) generare un'eccezione.

La soluzione alternativa è utilizzare le funzioni anonime denominate, se si perdona l'ossimoro. Davvero dovrei dire "named function expressions". Un esempio:

function someFunc(){ 
    return function funcExpressionName(args){ 
    if (this instanceof funcExpressionName) { 
     // do something 
    } else 
     return new funcExpressionName(arguments); 
    }; 
} 

Il nome specificato, nel mio esempio funcExpressionName non è dovrebbe essere accessibile da ovunque tranne all'interno della funzione si applica a, ma purtroppo IE ha altre idee (come si può vedere se si Google it) .

Per l'esempio nella tua domanda non sono sicuro di come gestire lo args.callee poiché non so come sia impostato dalla funzione di chiamata, ma l'uso di arguments.callee verrà sostituito come nel mio esempio.

1

Il codice originale di John Resig ha esito negativo con un costruttore senza parametri.

var Timestamp = makeClass(); 
Timestamp.prototype.init = function() { 
    this.value = new Date(); 
}; 

// ok 
var timestamp = Timestamp(); 
alert(timestamp.value); 

// TypeError: args is undefined 
var timestamp = new Timestamp(); 
alert(timestamp.value); 

Ma può essere riparato utilizzando la seguente riga

this.init.apply(this, args && args.callee ? args : arguments); 
2

È possibile che questo idea data dalla nnnnnn è abbastanza buono. E per evitare problemi di IE suggerisco la seguente soluzione.

function makeClassStrict() { 
    var isInternal, instance; 

    var constructor = function(args) { 
     // Find out whether constructor was called with 'new' operator. 
     if (this instanceof constructor) { 
      // When an 'init' method exists, apply it to the context object. 
      if (typeof this.init == "function") { 
       // Ask private flag whether we did the calling ourselves. 
       this.init.apply(this, isInternal ? args : arguments); 
      } 
     } else { 
      // We have an ordinary function call. 

      // Set private flag to signal internal instance creation. 
      isInternal = true;           
      instance = new constructor(arguments); 
      isInternal = false;           
      return instance; 
     } 
    }; 

    return constructor; 
} 

Si noti come si evita riferimento args.callee nella parte // do something utilizzando un flag interno.