2013-07-25 22 views
6

Sto lavorando con un'API RESTful e il mio codice Javascript sta effettuando query REST tramite la chiamata $ .ajax() di jQuery.Dichiarazione costante prototipo Javascript

Ho implementato una classe javascript riposo, che vi mostrerò di seguito (molto semplificata):

var Rest = function (baseUrlPath, errorMessageHandler) { 
     ... 
    }; 

// Declare HTTP response codes as constants 
Rest.prototype.STATUS_OK = 200; 
Rest.prototype.STATUS_BAD_REQUEST = 400; 

... // other rest methods 

Rest.prototype.post = function (params) { 
     $.ajax({ 
      type: 'POST', 
      url: params.url, 
      data: params.data, 
      dataType: 'json', 
      contentType: 'application/json; charset=utf-8', 
      beforeSend: this._authorize, 
      success: params.success, 
      error: params.error || this._getAjaxErrorHandler(params.errorMessage) 
     }); 
     }; 

... // more rest methods 

Rest.prototype.executeScenario = function (scenarioRef) { 
     var self = this; 

     this.post({ 
      url: 'myurlgoeshere', 
      data: 'mydatagoeshere', 
      success: function (data, textStatus, xhr) { 
       if (xhr.status == 200) { 
        console.log("everything went ok"); 
       } 
      }, 
      error: function (xhr, textStatus, errorMsg) { 
       // TODO: constants 
       if (404 == xhr.status) { 
        self.errorMessageHandler("The scenario does not exist or is not currently queued"); 
       } else if (403 == xhr.status) { 
        self.errorMessageHandler("You are not allowed to execute scenario: " + scenarioRef.displayName); 
       } else if(423 == xhr.status) { 
        self.errorMessageHandler("Scenario: " + scenarioRef.displayName + " is already in the queue"); 
       } 
      } 
     }); 
    }; 

il codice funziona come previsto, ma ho deciso di aggiungere alcune costanti per aiutare abbellire il codice e migliorare leggibilità. Ho per esempio diversi posti nel mio codice dove sto verificando xhr.status == 200 o xhr.status == 400 e così via.

mi può dichiarare variabili di classe come Rest.prototype.STATUS_OK = 200;

Ma variabile è modificabile, e non posso pensare a come farli costante. Per esempio nel mio codice posso fare un this.STATUS_OK = 123; e questo modificherà la variabile. Ho giocato con la parola chiave const, senza fortuna.

ho visto questo: Where to declare class constants?, ma non è stato di grande aiuto.

Qualcuno può indicarmi la giusta direzione su come rendere questi campi un valore letterale costante anziché una variabile?

+0

Si noti che i "campi" sono * proprietà *, non * variabili *. Per le variabili potresti semplicemente usare la [parola chiave 'const'] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const) dove supportata. Ma lo faresti localmente comunque :-) – Bergi

risposta

8

Utilizzo di Object.defineProperty ECMAScript 5 è possibile effettuare un valore non-impostabile:

Object.defineProperty(Rest, "STATUS_OK", { 
    enumerable: false, // optional; if you care about your enumerated keys 
    configurable: false, 
    writable: false, 
    value: 200 
}); 

Oppure, dal momento che questi sono i valori di default, semplicemente:

Object.defineProperty(Rest, "STATUS_OK", { value: 200 }); 

Questo rende Rest.STATUS_OK resa 01.238.quando si accede, ma non risponderà ai tentativi di ridefinirlo o delete it. Inoltre, configurable: false impedirà qualsiasi tentativo di ridefinire la proprietà con una successiva chiamata defineProperty.

Tuttavia, questo non funziona in older browsers that don't support ES5's defineProperty (in particolare IE8 e versioni precedenti).

+0

Questa è una buona soluzione, ma sembra un kludge dover scrivere diverse righe di codice (conosco la sua unica affermazione, ma ancora diverse righe per la leggibilità) per impostare una singola costante. E sicuramente un sacco di lavoro quando hai molte costanti da dichiarare. Forse in futuro ci sarà un supporto migliore in quanto IE8 e successivi verranno gradualmente eliminati. – Husman

+5

@Husman: In realtà è possibile omettere tutte le righe ma il valore "value", poiché "false" è l'impostazione predefinita per quelle. – Bergi

+0

@Bergi Buona chiamata; Ho modificato la mia risposta in base al tuo suggerimento. – apsillers

1

Questo non sarà possibile in Javascript. La cosa migliore probabilmente si potrebbe fare, è creare un po 'di chiusura come roba:

var StatusCode = (function() { 
    var STATUS_OK = 200, 
     STATUS_BAD_REQUEST = 400; 

    return { 
     getOk: function() { 
      return STATUS_OK; 
     }, 
     getBadRequest: function() { 
      return STATUS_BAD_REQUEST; 
     } 
    } 

}); 

e usarlo come StatusCode.getOk() === 200. Questo ti aiuterà a non essere in grado di cambiare quelle "costanti", ma sarà di nuovo negativo per la tua leggibilità (questo è probabilmente basato sull'opinione pubblica). Vorrei semplicemente mantenere costanti quelle costanti per contrassegnarle come costanti, sebbene potessero essere modificate.

+1

+1; Inoltre, non c'è ragione per cui qualcuno non possa semplicemente sovrascrivere 'getOk' con' function() {return "qualcos'altro"; } '. – apsillers

+1

@apsillers buon punto. Come linea di fondo, non puoi proteggere in sicurezza nulla in javascript. Esempio tipico: anche "non definito" può essere sovrascritto. –

1

È possibile definire gli stati come getter, ma AFAIK non funzionerà in IE8 e versioni precedenti.

var Rest = function (baseUrlPath, errorMessageHandler) { 
     this.STATUS_OK = 123; // trying to override. 
    }; 

// Declare HTTP response codes as constants 
Rest.prototype = { 
    get STATUS_OK(){ return 200; }, 
    get STATUS_BAD_REQUEST(){ return 400; } 
} 

var client = new Rest(); 
console.log(client.STATUS_OK); // 200! 
client.STATUS_OK = 123; 
console.log(client.STATUS_OK); // still 200! 

Altro su getter e setter: http://ejohn.org/blog/javascript-getters-and-setters/

+0

'Object.defineProperty (Rest.prototype," STATUS_OK ", {get: function() {return 123;}});' e sei fuori :-) – Bergi

0

Javascript non ha un buon supporto per creare costanti immutabili. Anche la parola chiave const non è consigliata perché non funziona in alcuni browser.

Penso che il modo migliore todo sta usando Object.freeze:

Rest.Status = {}; 
Rest.Status.Ok = "Ok"; 
Object.freeze(Rest.Status); 

Object.freeze ignorerà silenziosa cambiamenti nell'oggetto di stato. Di Esempio:

Rest.Status.Ok = "foo"; 
Rest.Status.Ok; //=> "Ok" 

Ma proprio lavorare in ECMAScript 5 o superiore.

Sopra ho messo lo stato in un oggetto Status, penso che sia più interessante di prototype, perché prototipo è più vicino ai metodi di istanza, proprietà ecc e l'oggetto di stato visto come un'enumerazione.

+0

Si noti che questo consente ancora la riassegnazione della proprietà 'Rest.Status' a un oggetto completamente diverso. – apsillers

+0

Sì, non me ne sono reso conto. Un'alternativa sarebbe creare un oggetto RestStatus, ma in questo modo esistono due variabili globali :( –

Problemi correlati