Opprette en singleton fra enhver klasse i javascript

stemmer
0

Jeg har skrevet følgende funksjon som tillater etablering av singleton klasser fra gitte klasser:

function SingletonFrom(Constructor) {
    return function() {
        var self = arguments.callee;
        if (self._instance === undefined) {
            switch (arguments.length) { // this is ugly
                case  0: self._instance = new Constructor(); break;
                case  1: self._instance = new Constructor(arguments[0]); break;
                case  2: self._instance = new Constructor(arguments[0], arguments[1]); break;
                // [...]
                case 10: // ...
                default: throw new Error('Error in Singleton: Constructor may take at most 10 arguments'); break;
            }
        }
        return self._instance;
    }
}

Eksempel:

var Array_Singleton = new SingletonFrom(Array);
var x = new Array_Singleton(1,2,3);   // [1,2,3]
var y = new Array_Singleton(0,0,0,0); // [1,2,3]
alert(x === y); // true

Det fungerer bra, men jeg er ikke helt fornøyd med switchuttalelsen. Problemet er bestått et variabelt antall argumenter til en konstruktør kalles med new søkeordet er ikke mulig. Så må min Constructor funksjonen ikke ta mer enn 10 argumenter. For eksempel vil dette mislykkes:

new Array_Singleton(1,2,3,4,5,6,7,8,9,10,11);

Noen måte å omgå dette?

Publisert på 23/09/2009 klokken 13:02
kilden bruker
På andre språk...                            


2 svar

stemmer
0

Av toppen av hodet mitt, kan jeg bare tenke på ett og jeg ville nok ikke anbefale det uten en ekstremt heftig mengde testing .

Når det er sagt; stedet for å gå i parameterene separat, passere dem som en matrise. Du kan deretter iterere gjennom rekke og bygge en streng med din oppfordring til new. Når du har din streng, kan du ringe eval()for å drive generert kommando.

Det vil gi deg en måte å håndtere enhver dynamisk rekke parametere.

Svarte 23/09/2009 kl. 13:10
kilden bruker

stemmer
1

Javascript har denne irriterende begrensning av ikke å kunne ringe konstruktøren med en rekke som en liste med argumenter. Hva er vanligvis oppnås med Function.prototype.applynår du ringer funksjon som en funksjon (f.eks foo(...)), ikke enkelt kan brukes til en funksjon når det heter som konstruktør (f.eks new foo(...)).

Jeg gjetter dette er nøyaktig hvorfor du ty til switchdet.

function foo(a,b) {
  return a+b;
}
foo.apply(null, [1,2]); // 3

Men det er ikke så lett med konstruktøren:

function Person(fname, lname) {
  this.fname = fname;
  this.lname = lname;
}
Person.prototype.speak = function() {
  return 'Hi. My name is: ' + this.fname + ' ' + this.lname;
}

new Person.apply(null, ['John', 'Appleseed']); // doesn't work!

For å omgå dette, kan du lage en enkel medhjelper som ville praktisk talt simulere hva newgjør , bare denne gangen med apply. Algoritmen er rett-frem;

  1. Opprett en tom objekt med riktig prototype kjeden, men ikke kalle konstruktøren på den.
  2. Bruk applytil å ringe konstruktøren i sammenheng med denne nyopprettede objektet, passerer den argumentliste med apply.

Det vil se omtrent slik ut:

function newApply(ctr, array) {
  function F(){}
  F.prototype = ctr.prototype;
  var obj = new F();
  ctr.apply(obj, array);
  return obj;
}
newApply(Person, ['John', 'Appleseed']); // returns new object

Alternativt kan du unngå Fobjekt skapelse under kjøring for å spare på ytelse og minneforbruk :

var newApply = (function(){
  function F(){}
  return function(ctr, array) {
    F.prototype = ctr.prototype;
    var obj = new F();
    ctr.apply(obj, array);
    return obj;
  }
})();
Svarte 23/09/2009 kl. 13:53
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more