Есть ли константы в JavaScript? - PullRequest
       115

Есть ли константы в JavaScript?

1106 голосов
/ 25 сентября 2008

Есть ли способ использовать константы в JavaScript?

Если нет, какова общая практика определения переменных, которые используются в качестве констант?

Ответы [ 33 ]

17 голосов
/ 30 декабря 2013

Если вы не возражаете против использования функций:

var constant = function(val) {
   return function() {
        return val;
    }
}

Этот подход дает вам функции вместо обычных переменных, но он гарантирует *, что никто не сможет изменить значение после его установки.

a = constant(10);

a(); // 10

b = constant(20);

b(); // 20

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

* Если кто-то не переопределил функцию constant до того, как вы ее вызвали

14 голосов
/ 02 июля 2015

Группируйте константы в структуры, где это возможно:

Пример, в моем текущем игровом проекте, я использовал ниже:

var CONST_WILD_TYPES = {
    REGULAR: 'REGULAR',
    EXPANDING: 'EXPANDING',
    STICKY: 'STICKY',
    SHIFTING: 'SHIFTING'
};

Назначение:

var wildType = CONST_WILD_TYPES.REGULAR;

Comparision:

if (wildType === CONST_WILD_TYPES.REGULAR) {
    // do something here
}

В последнее время я использую для сравнения:

switch (wildType) {
    case CONST_WILD_TYPES.REGULAR:
        // do something here
        break;
    case CONST_WILD_TYPES.EXPANDING:
        // do something here
        break;
}

IE11 с новым стандартом ES6, который имеет декларацию const.
Выше работает в более ранних браузерах, таких как IE8, IE9 и IE10.

12 голосов
/ 19 июля 2011

Забудьте IE и используйте ключевое слово const.

12 голосов
/ 08 апреля 2011

Вы можете легко снабдить свой сценарий механизмом для констант, которые можно устанавливать, но не изменять. Попытка изменить их приведет к ошибке.

/* author Keith Evetts 2009 License: LGPL  
anonymous function sets up:  
global function SETCONST (String name, mixed value)  
global function CONST (String name)  
constants once set may not be altered - console error is generated  
they are retrieved as CONST(name)  
the object holding the constants is private and cannot be accessed from the outer script directly, only through the setter and getter provided  
*/

(function(){  
  var constants = {};  
  self.SETCONST = function(name,value) {  
      if (typeof name !== 'string') { throw new Error('constant name is not a string'); }  
      if (!value) { throw new Error(' no value supplied for constant ' + name); }  
      else if ((name in constants) ) { throw new Error('constant ' + name + ' is already defined'); }   
      else {   
          constants[name] = value;   
          return true;  
    }    
  };  
  self.CONST = function(name) {  
      if (typeof name !== 'string') { throw new Error('constant name is not a string'); }  
      if ( name in constants ) { return constants[name]; }    
      else { throw new Error('constant ' + name + ' has not been defined'); }  
  };  
}())  


// -------------  demo ----------------------------  
SETCONST( 'VAT', 0.175 );  
alert( CONST('VAT') );


//try to alter the value of VAT  
try{  
  SETCONST( 'VAT', 0.22 );  
} catch ( exc )  {  
   alert (exc.message);  
}  
//check old value of VAT remains  
alert( CONST('VAT') );  


// try to get at constants object directly  
constants['DODO'] = "dead bird";  // error  
9 голосов
/ 06 февраля 2013

Тем не менее, нет точного предопределенного кросс-браузерного способа сделать это, вы можете достичь этого, контролируя область действия переменных, как показано в других ответах.

Но я предлагаю использовать пространство имен, чтобы отличать его от других переменных. это уменьшит вероятность столкновения до минимума от других переменных.

Правильное пространство имен, как

var iw_constant={
     name:'sudhanshu',
     age:'23'
     //all varibale come like this
}

, поэтому при использовании он будет iw_constant.name или iw_constant.age

Вы также можете заблокировать добавление любого нового ключа или изменение любого ключа внутри iw_constant с помощью метода Object.freeze. Однако это не поддерживается в устаревшем браузере.

например:

Object.freeze(iw_constant);

Для старых браузеров вы можете использовать polyfill для метода замораживания.


Если вы согласны с вызовом функции, лучше всего использовать кросс-браузерный способ определения константы. Определение объема вашего объекта в пределах самореализующейся функции и возвращение функции get для ваших констант например:

var iw_constant= (function(){
       var allConstant={
             name:'sudhanshu',
             age:'23'
             //all varibale come like this

       };

       return function(key){
          allConstant[key];
       }
    };

// чтобы получить значение используйте iw_constant('name') или iw_constant('age')


** В обоих примерах вы должны быть очень осторожны с интервалом имен, чтобы ваш объект или функция не заменялись другой библиотекой. (Если будет заменен сам объект или функция, вся ваша константа будет работать)

7 голосов
/ 25 сентября 2008

Некоторое время я указывал «константы» (которые на самом деле не были константами) в литералах объекта, передаваемых в операторы with(). Я думал, что это было так умно. Вот пример:

with ({
    MY_CONST : 'some really important value'
}) {
    alert(MY_CONST);
}

В прошлом я также создавал пространство имен CONST, в которое я помещал бы все свои константы. Опять же с накладными расходами. Sheesh.

Теперь я просто делаю var MY_CONST = 'whatever'; до KISS .

6 голосов
/ 29 октября 2012

Мое мнение (работает только с объектами).

var constants = (function(){
  var a = 9;

  //GLOBAL CONSTANT (through "return")
  window.__defineGetter__("GCONST", function(){
    return a;
  });

  //LOCAL CONSTANT
  return {
    get CONST(){
      return a;
    }
  }
})();

constants.CONST = 8; //9
alert(constants.CONST); //9

Попробуйте! Но поймите - это объект, а не простая переменная.

Попробуйте также просто:

const a = 9;
5 голосов
/ 11 ноября 2012

Очевидно, что это указывает на необходимость стандартизированного кросс-браузерного ключевого слова const.

А пока:

var myconst = value;

или

Object['myconst'] = value;

Оба кажутся достаточными, а все остальное похоже на стрельбу из мухи из базуки.

5 голосов
/ 03 августа 2012

У меня тоже была проблема с этим. И после долгого времени поиска ответа и просмотра всех ответов всех, я думаю, я нашел жизнеспособное решение для этого.

Кажется, что большинство ответов, которые я встречал, использует функции для хранения констант. Как пишут многие пользователи форумов MANY, функции могут быть легко переписаны пользователями на стороне клиента. Меня заинтриговал ответ Кейта Эветса о том, что объект констант не может быть доступен извне, но только из внутренних функций.

Итак, я придумал это решение:

Поместите все внутри анонимной функции, чтобы клиентская сторона не могла изменять переменные, объекты и т. Д. Также скрывайте «реальные» функции, заставляя другие функции вызывать «реальные» функции изнутри. Я также подумал об использовании функций для проверки, была ли функция изменена пользователем на стороне клиента. Если функции были изменены, измените их обратно, используя переменные, которые «защищены» внутри и не могут быть изменены.

/*Tested in: IE 9.0.8; Firefox 14.0.1; Chrome 20.0.1180.60 m; Not Tested in Safari*/

(function(){
  /*The two functions _define and _access are from Keith Evetts 2009 License: LGPL (SETCONST and CONST).
    They're the same just as he did them, the only things I changed are the variable names and the text
    of the error messages.
  */

  //object literal to hold the constants
  var j = {};

  /*Global function _define(String h, mixed m). I named it define to mimic the way PHP 'defines' constants.
    The argument 'h' is the name of the const and has to be a string, 'm' is the value of the const and has
    to exist. If there is already a property with the same name in the object holder, then we throw an error.
    If not, we add the property and set the value to it. This is a 'hidden' function and the user doesn't
    see any of your coding call this function. You call the _makeDef() in your code and that function calls
    this function.    -    You can change the error messages to whatever you want them to say.
  */
  self._define = function(h,m) {
      if (typeof h !== 'string') { throw new Error('I don\'t know what to do.'); }
      if (!m) { throw new Error('I don\'t know what to do.'); }
      else if ((h in j) ) { throw new Error('We have a problem!'); }
      else {
          j[h] = m;
          return true;
    }
  };

  /*Global function _makeDef(String t, mixed y). I named it makeDef because we 'make the define' with this
    function. The argument 't' is the name of the const and doesn't need to be all caps because I set it
    to upper case within the function, 'y' is the value of the value of the const and has to exist. I
    make different variables to make it harder for a user to figure out whats going on. We then call the
    _define function with the two new variables. You call this function in your code to set the constant.
    You can change the error message to whatever you want it to say.
  */
  self._makeDef = function(t, y) {
      if(!y) { throw new Error('I don\'t know what to do.'); return false; }
      q = t.toUpperCase();
      w = y;
      _define(q, w);
  };

  /*Global function _getDef(String s). I named it getDef because we 'get the define' with this function. The
    argument 's' is the name of the const and doesn't need to be all capse because I set it to upper case
    within the function. I make a different variable to make it harder for a user to figure out whats going
    on. The function returns the _access function call. I pass the new variable and the original string
    along to the _access function. I do this because if a user is trying to get the value of something, if
    there is an error the argument doesn't get displayed with upper case in the error message. You call this
    function in your code to get the constant.
  */
  self._getDef = function(s) {
      z = s.toUpperCase();
      return _access(z, s);
  };

  /*Global function _access(String g, String f). I named it access because we 'access' the constant through
    this function. The argument 'g' is the name of the const and its all upper case, 'f' is also the name
    of the const, but its the original string that was passed to the _getDef() function. If there is an
    error, the original string, 'f', is displayed. This makes it harder for a user to figure out how the
    constants are being stored. If there is a property with the same name in the object holder, we return
    the constant value. If not, we check if the 'f' variable exists, if not, set it to the value of 'g' and
    throw an error. This is a 'hidden' function and the user doesn't see any of your coding call this
    function. You call the _getDef() function in your code and that function calls this function.
    You can change the error messages to whatever you want them to say.
  */
  self._access = function(g, f) {
      if (typeof g !== 'string') { throw new Error('I don\'t know what to do.'); }
      if ( g in j ) { return j[g]; }
      else { if(!f) { f = g; } throw new Error('I don\'t know what to do. I have no idea what \''+f+'\' is.'); }
  };

  /*The four variables below are private and cannot be accessed from the outside script except for the
    functions inside this anonymous function. These variables are strings of the four above functions and
    will be used by the all-dreaded eval() function to set them back to their original if any of them should
    be changed by a user trying to hack your code.
  */
  var _define_func_string = "function(h,m) {"+"      if (typeof h !== 'string') { throw new Error('I don\\'t know what to do.'); }"+"      if (!m) { throw new Error('I don\\'t know what to do.'); }"+"      else if ((h in j) ) { throw new Error('We have a problem!'); }"+"      else {"+"          j[h] = m;"+"          return true;"+"    }"+"  }";
  var _makeDef_func_string = "function(t, y) {"+"      if(!y) { throw new Error('I don\\'t know what to do.'); return false; }"+"      q = t.toUpperCase();"+"      w = y;"+"      _define(q, w);"+"  }";
  var _getDef_func_string = "function(s) {"+"      z = s.toUpperCase();"+"      return _access(z, s);"+"  }";
  var _access_func_string = "function(g, f) {"+"      if (typeof g !== 'string') { throw new Error('I don\\'t know what to do.'); }"+"      if ( g in j ) { return j[g]; }"+"      else { if(!f) { f = g; } throw new Error('I don\\'t know what to do. I have no idea what \\''+f+'\\' is.'); }"+"  }";

  /*Global function _doFunctionCheck(String u). I named it doFunctionCheck because we're 'checking the functions'
    The argument 'u' is the name of any of the four above function names you want to check. This function will
    check if a specific line of code is inside a given function. If it is, then we do nothing, if not, then
    we use the eval() function to set the function back to its original coding using the function string
    variables above. This function will also throw an error depending upon the doError variable being set to true
    This is a 'hidden' function and the user doesn't see any of your coding call this function. You call the
    doCodeCheck() function and that function calls this function.    -    You can change the error messages to
    whatever you want them to say.
  */
  self._doFunctionCheck = function(u) {
      var errMsg = 'We have a BIG problem! You\'ve changed my code.';
      var doError = true;
      d = u;
      switch(d.toLowerCase())
      {
           case "_getdef":
               if(_getDef.toString().indexOf("z = s.toUpperCase();") != -1) { /*do nothing*/ }
               else { eval("_getDef = "+_getDef_func_string); if(doError === true) { throw new Error(errMsg); } }
               break;
           case "_makedef":
               if(_makeDef.toString().indexOf("q = t.toUpperCase();") != -1) { /*do nothing*/ }
               else { eval("_makeDef = "+_makeDef_func_string); if(doError === true) { throw new Error(errMsg); } }
               break;
           case "_define":
               if(_define.toString().indexOf("else if((h in j) ) {") != -1) { /*do nothing*/ }
               else { eval("_define = "+_define_func_string); if(doError === true) { throw new Error(errMsg); } }
               break;
           case "_access":
               if(_access.toString().indexOf("else { if(!f) { f = g; }") != -1) { /*do nothing*/ }
               else { eval("_access = "+_access_func_string); if(doError === true) { throw new Error(errMsg); } }
               break;
           default:
                if(doError === true) { throw new Error('I don\'t know what to do.'); }
      }
  };

  /*Global function _doCodeCheck(String v). I named it doCodeCheck because we're 'doing a code check'. The argument
    'v' is the name of one of the first four functions in this script that you want to check. I make a different
    variable to make it harder for a user to figure out whats going on. You call this function in your code to check
    if any of the functions has been changed by the user.
  */
  self._doCodeCheck = function(v) {
      l = v;
      _doFunctionCheck(l);
  };
}())

Также кажется, что безопасность - это действительно проблема, и нет способа «спрятать» ваше программирование от клиентской стороны. Хорошая идея для меня - сжать ваш код так, чтобы любому, включая вас, программиста, было действительно трудно его прочитать и понять. Есть сайт, на который вы можете перейти: http://javascriptcompressor.com/. (Это не мой сайт, не беспокойтесь, я не рекламирую.) Это сайт, который позволит вам сжимать и запутывать код Javascript бесплатно.

  1. Скопируйте весь код в приведенном выше сценарии и вставьте его в верхнюю область текста на странице javascriptcompressor.com.
  2. Установите флажок кодирования Base62, установите флажок Сокращать переменные.
  3. Нажмите кнопку сжатия.
  4. Вставьте и сохраните все это в файл .js и добавьте его на свою страницу в верхней части страницы.
4 голосов
/ 13 июня 2016

JavaScript ES6 (повторно) ввел ключевое слово const , которое поддерживается во всех основных браузерах 1005 *.

Переменные, объявленные с помощью const, не могут быть повторно объявлены или переназначены.

Кроме того, const ведет себя подобно let.

Он ведет себя, как и ожидалось, для примитивных типов данных (логический, ноль, неопределенный, число, строка, символ):

const x = 1;
x = 2;
console.log(x); // 1 ...as expected, re-assigning fails

Внимание: Помните о подводных камнях в отношении объектов:

const o = {x: 1};
o = {x: 2};
console.log(o); // {x: 1} ...as expected, re-assigning fails

o.x = 2;
console.log(o); // {x: 2} !!! const does not make objects immutable!

const a = [];
a = [1];
console.log(a); // 1 ...as expected, re-assigning fails

a.push(1);
console.log(a); // [1] !!! const does not make objects immutable

Если вам действительно нужен неизменный и абсолютно постоянный объект: просто используйте const ALL_CAPS, чтобы прояснить свое намерение. В любом случае, это хорошее соглашение для всех const объявлений, поэтому просто полагайтесь на него.

...