2012-01-29 11 views
7

referencyjny: http://ejohn.org/blog/simple-class-instantiation/Johna Resig Prosta klasa instancji i „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); 
    }; 
} 

Zastanawiałem się, czy są jakieś ECMAScript 5 sposób zgodny wdrożyć taką samą funkcjonalność. Problem polega na tym, że uzyskanie dostępu do arguments.callee jest przestarzałe w trybie ścisłym.

Odpowiedz

4

Jak rozumiem, arguments.callee nie jest przestarzałe w trybie ścisłym, w takim przypadku można nadal z niego korzystać; raczej został usunięty i próba użycia spowoduje (lub ma na celu) wyrzucenie wyjątku.

Obejście polega na użyciu nazwanych anonimowych funkcji, jeśli wybaczycie oksymoronowi. Naprawdę powinienem powiedzieć "named function expressions". Przykład:

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

Nazwa podasz, w moim przykładzie funcExpressionName nie powinien być dostępny z dowolnego miejsca z wyjątkiem wewnątrz funkcji to dotyczy, ale niestety IE ma inne pomysły (jak widać, jeśli Google it) .

Dla przykładu na twoje pytanie nie jestem pewien, jak obsługiwać args.callee, ponieważ nie wiem, jak to jest ustawione przez funkcję wywołującą, ale użycie arguments.callee zostanie zastąpiony jak na mój przykład.

1

Oryginalny kod Johna Resiga kończy się niepowodzeniem z konstruktorem bez parametrów.

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); 

Ale może to być naprawione przy użyciu poniższego wiersza

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

Powyższa idea podane przez nnnnnn jest dość dobry. Aby uniknąć problemów związanych z IE, sugeruję następujące rozwiązanie.

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; 
} 

Uwaga, w jaki sposób uniknąć odniesień do args.callee w // do something części za pomocą wewnętrznego flagę.

Powiązane problemy