2013-07-25 3 views
6

Я работаю с RESTful API, а мой Javascript-код делает запросы REST через вызов $ .ajax() jQuery.Объявление константы прототипа Javascript

я реализовал яваскрипта класс Rest, который я покажу ниже (сильно упрощены):

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

код работает, как задумано, однако я решил добавить некоторые константы, чтобы помочь украсить код и улучшить читаемость. У меня есть несколько мест в моем коде, где я проверяю xhr.status == 200 или xhr.status == 400 и так далее.

я могу объявить переменные класса, как Rest.prototype.STATUS_OK = 200;

Но переменная редактируется, и я не могу думать о том, как сделать их постоянными. В моем коде, например, я могу сделать this.STATUS_OK = 123;, и это изменит эту переменную. Я играл с ключевым словом const, без везения.

Я видел это: Where to declare class constants?, но это не помогло.

Может ли кто-нибудь указать мне в правильном направлении, как сделать эти поля постоянным литералом вместо переменной?

+0

Обратите внимание, что «поля» - это * свойства *, а не * переменные *. Для переменных вы просто можете использовать ключевое слово ['const'] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const), где это поддерживается. Но в любом случае вы будете локально-scope :-) – Bergi

ответ

8

Использование ECMAScript 5-х Object.defineProperty вы можете сделать значение не-устанавливаемое:

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

Или, так как те значения по умолчанию, просто сделать:

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

Это делает Rest.STATUS_OK выход 200 при доступе, но он не будет отвечать на попытки переопределить его или delete. Кроме того, configurable: false предотвратит любую попытку переопределить свойство с последующим вызовом defineProperty.

Однако это не работает в older browsers that don't support ES5's defineProperty (особенно IE8 и ниже).

+0

Это хороший способ обхода, но это похоже на kludge нужно написать несколько строк кода (я знаю его одно утверждение, но еще несколько строк для удобочитаемости), чтобы установить одну константу. И определенно много работы, когда у вас много констант для объявления. Возможно, в будущем это будет лучше, так как IE8 и ниже будут постепенно отменены. – Husman

+5

@ Husman: На самом деле вы можете опустить все строки, кроме 'value', так как для них используется значение false. – Bergi

+0

@Bergi Хороший звонок; Я отредактировал свой ответ в соответствии с вашим предложением. – apsillers

1

Это не возможно в Javascript. Лучшее, что вы могли бы, вероятно, это создать некоторое закрытие как материал:

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

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

}); 

И использовать его как StatusCode.getOk() === 200. Это поможет вам не изменять эти «константы», но опять же будет плохо для вашей читаемости (возможно, это основано на мнениях). Я бы просто сохранил эти константы в верхнем регистре, чтобы отметить их как постоянные, хотя их можно было изменить.

+1

+1; Кроме того, нет причин, по которым кто-то не мог просто переписать 'getOk' с помощью функции() {return« something else »; } '. – apsillers

+1

@ переходы хорошая точка. В нижней строке вы не можете безопасно защитить что-либо в javascript. Типичный пример - даже «undefined» можно переопределить. –

1

Вы можете определить статусы как геттеры, но AFAIK это не будет работать в IE8 и старше.

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! 

Больше на добытчиками и сеттеров: http://ejohn.org/blog/javascript-getters-and-setters/

+0

'Object.defineProperty (Rest.prototype,« STATUS_OK », {get: function() {return 123;}});' и вы отсутствуете :-) – Bergi

0

Javascript не имеет хорошей поддержки для создания неизменяемых констант. Даже ключевое слово const не рекомендуется, так как оно не работает в некоторых браузерах.

Я думаю, что лучший способ TODO он использует Object.freeze:

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

Object.freeze будет молчать игнорировать изменения в объекте состояния. К примеру:

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

Но просто работать в ECMAScript 5 или выше.

Выше я поместил статус Status объекта, я думаю, что это более интересно, чем prototype, потому что прототип более близок к методам экземпляра, свойство и т.д. и объекту состояния рассматривается как перечисление.

+0

Обратите внимание, что это все еще позволяет переназначить свойство 'Rest.Status' совершенно другому объекту. – apsillers

+0

Да, я этого не осознал. Один из альтернатив мог бы создать объект RestStatus, но в этом случае будут существовать две глобальные переменные :( –