Есть ли константы в JavaScript?
Есть ли способ использовать константы в JavaScript?
Если нет, какова общая практика определения переменных, которые используются в качестве констант?
33 ответа
Начиная с ES2015, JavaScript имеет понятие const
:
const MY_CONSTANT = "some-value";
Это будет работать практически во всех браузерах, кроме IE 8, 9 и 10. Некоторым также может понадобиться строгий режим.
Ты можешь использовать var
с такими соглашениями, как ALL_CAPS, чтобы показать, что определенные значения не должны изменяться, если вам нужно поддерживать старые браузеры или работать с устаревшим кодом:
var MY_CONSTANT = "some-value";
Вы пытаетесь защитить переменные от модификации? Если это так, то вы можете использовать шаблон модуля:
var CONFIG = (function() {
var private = {
'MY_CONST': '1',
'ANOTHER_CONST': '2'
};
return {
get: function(name) { return private[name]; }
};
})();
alert('MY_CONST: ' + CONFIG.get('MY_CONST')); // 1
CONFIG.MY_CONST = '2';
alert('MY_CONST: ' + CONFIG.get('MY_CONST')); // 1
CONFIG.private.MY_CONST = '2'; // error
alert('MY_CONST: ' + CONFIG.get('MY_CONST')); // 1
Используя этот подход, значения не могут быть изменены. Но вы должны использовать метод get() для CONFIG:(.
Если вам не нужно строго защищать значение переменных, просто сделайте, как предложено, и используйте соглашение ALL CAPS.
const
Ключевое слово в черновике ECMAScript 6, но пока оно пользуется лишь незначительной поддержкой браузера: http://kangax.github.io/compat-table/es6/. Синтаксис:
const CONSTANT_NAME = 0;
"use strict";
var constants = Object.freeze({
"π": 3.141592653589793 ,
"e": 2.718281828459045 ,
"i": Math.sqrt(-1)
});
constants.π; // -> 3.141592653589793
constants.π = 3; // -> TypeError: Cannot assign to read only property 'π' …
constants.π; // -> 3.141592653589793
delete constants.π; // -> TypeError: Unable to delete property.
constants.π; // -> 3.141592653589793
Смотрите Object.freeze. Вы можете использоватьconst
если вы хотите сделать constants
ссылка только для чтения.
IE поддерживает константы, например:
<script language="VBScript">
Const IE_CONST = True
</script>
<script type="text/javascript">
if (typeof TEST_CONST == 'undefined') {
const IE_CONST = false;
}
alert(IE_CONST);
</script>
ECMAScript 5 действительно вводит Object.defineProperty
:
Object.defineProperty (window,'CONSTANT',{ value : 5, writable: false });
Он поддерживается в любом современном браузере (а также IE ≥ 9).
Смотрите также: Object.defineProperty в ES5?
Нет не вообще. Firefox реализует const
но я знаю, что IE нет.
@John указывает на обычную практику именования для conts, которая годами использовалась на других языках, и я не вижу причин, почему вы не могли бы это использовать. Конечно, это не значит, что кто-то не будет переписывать значение переменной в любом случае.:)
В JavaScript я предпочитаю использовать функции для возврата постоянных значений.
function MY_CONSTANT() {
return "some-value";
}
alert(MY_CONSTANT());
Документы Mozillas MDN Web содержат хорошие примеры и пояснения о const
, Выдержка:
// define MY_FAV as a constant and give it the value 7
const MY_FAV = 7;
// this will throw an error - Uncaught TypeError: Assignment to constant variable.
MY_FAV = 20;
Но это печально, что IE9/10 по-прежнему не поддерживает const
, И причина это абсурдно
Итак, что IE9 делает с const? До сих пор мы решили не поддерживать его. Это еще не консенсусная функция, поскольку она никогда не была доступна во всех браузерах.
...
В конце концов, кажется, что лучшее долгосрочное решение для сети - это оставить его и ждать, пока процессы стандартизации начнут действовать.
Они не реализуют это, потому что другие браузеры не реализовали это правильно?! Слишком боишься сделать это лучше? Стандартные определения или нет, константа является константой: устанавливается один раз, никогда не изменяется.
И ко всем идеям: каждая функция может быть перезаписана (XSS и т. Д.). Так что нет никакой разницы в var
или же function(){return}
, const
это единственная настоящая константа.
Обновление:
IE11 поддерживает const
:
IE11 включает поддержку четко определенных и часто используемых функций нового стандарта ECMAScript 6, включая let,
const
,Map
,Set
, а такжеWeakMap
, так же как__proto__
для улучшения совместимости.
С помощью "нового" Object api вы можете сделать что-то вроде этого:
var obj = {};
Object.defineProperty(obj, 'CONSTANT', {
configurable: false
enumerable: true,
writable: false,
value: "your constant value"
});
взгляните на это в Mozilla MDN для получения дополнительной информации. Это не переменная первого уровня, так как она прикреплена к объекту, но если у вас есть область видимости, вы можете присоединить ее к этому. this
должно работать так же. Так, например, выполнение этого в глобальной области действия объявит псевдо-константное значение в окне (что является действительно плохой идеей, вы не должны небрежно объявлять глобальные переменные)
Object.defineProperty(this, 'constant', {
enumerable: true,
writable: false,
value: 7,
configurable: false
});
> constant
=> 7
> constant = 5
=> 7
примечание: назначение вернет вам назначенное значение в консоли, но значение переменной не изменится
Если вы не возражаете против использования функций:
var constant = function(val) {
return function() {
return val;
}
}
Этот подход дает вам функции вместо обычных переменных, но гарантирует *, что никто не сможет изменить значение после его установки.
a = constant(10);
a(); // 10
b = constant(20);
b(); // 20
Лично я нахожу это довольно приятным, особенно после того, как привык к этому шаблону из наблюдаемых нокаутов.
* Если кто-то не переопределил функцию constant
прежде чем ты позвонил
Группируйте константы в структуры, где это возможно:
Пример, в моем текущем игровом проекте, я использовал ниже:
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.
Вы можете легко снабдить свой сценарий механизмом для констант, которые могут быть установлены, но не изменены. Попытка изменить их приведет к ошибке.
/* 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
Тем не менее, нет точного кросс-браузерного предопределенного способа сделать это, вы можете достичь этого, контролируя область действия переменных, как показано в других ответах.
Но я предложу использовать пространство имен, чтобы отличать его от других переменных. это уменьшит вероятность столкновения до минимума от других переменных.
Правильное пространство имен, как
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 for freeze.
Если вы согласны с вызовом функции, лучше всего использовать кросс-браузерный способ определения константы. Определение области вашего объекта в пределах самореализующейся функции и возвращение функции get для ваших констант ex:
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')
** В обоих примерах вы должны быть очень осторожны с интервалом имен, чтобы ваш объект или функция не заменялись другой библиотекой.(Если будет заменен сам объект или функция, вся ваша константа будет работать)
Некоторое время я указывал "константы" (которые на самом деле не были константами) в объектных литералах, передаваемых в with()
заявления. Я думал, что это было так умно. Вот пример:
with ({
MY_CONST : 'some really important value'
}) {
alert(MY_CONST);
}
В прошлом я также создал CONST
пространство имен, в которое я бы поместил все свои константы. Опять же с накладными расходами. Sheesh.
Теперь я просто делаю var MY_CONST = 'whatever';
поцеловать
Мое мнение (работает только с объектами).
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;
Ясно, что это показывает необходимость стандартизированного кросс-браузерного ключевого слова const.
Но сейчас:
var myconst = value;
или же
Object['myconst'] = value;
И то, и другое кажется достаточным, а все остальное похоже на стрельбу из мухи из базуки.
У меня тоже была проблема с этим. И после долгого времени поиска ответа и просмотра всех ответов всех, я думаю, я нашел жизнеспособное решение для этого.
Кажется, что большинство ответов, которые я встречал, использует функции для хранения констант. Как пишут многие пользователи форумов 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 бесплатно.
- Скопируйте весь код в приведенном выше сценарии и вставьте его в верхнюю область текста на странице javascriptcompressor.com.
- Установите флажок кодирования Base62, установите флажок Сокращать переменные.
- Нажмите кнопку "Сжать".
- Вставьте и сохраните все это в файле.js и добавьте его на страницу в верхней части страницы.
Я использую const
вместо var
в моих скриптах Greasemonkey, но это потому, что они будут работать только на Firefox...
Соглашение об именах действительно может быть подходящим способом (я делаю и то и другое!).
Хорошо, это уродливо, но оно дает мне константу в Firefox и Chromium, непостоянную константу (WTF?) В Safari и Opera и переменную в IE.
Конечно, eval() - это зло, но без него IE выдает ошибку, мешающую запуску скриптов.
Safari и Opera поддерживают ключевое слово const, но вы можете изменить значение const.
В этом примере серверный код записывает JavaScript на страницу, заменяя {0} значением.
try{
// i can haz const?
eval("const FOO='{0}';");
// for reals?
var original=FOO;
try{
FOO='?NO!';
}catch(err1){
// no err from Firefox/Chrome - fails silently
alert('err1 '+err1);
}
alert('const '+FOO);
if(FOO=='?NO!'){
// changed in Sf/Op - set back to original value
FOO=original;
}
}catch(err2){
// IE fail
alert('err2 '+err2);
// set var (no var keyword - Chrome/Firefox complain about redefining const)
FOO='{0}';
alert('var '+FOO);
}
alert('FOO '+FOO);
Для чего это хорошо? Не так много, так как это не кросс-браузер. В лучшем случае, может быть, немного спокойствия, что по крайней мере некоторые браузеры не позволят букмарклетам или сторонним скриптам изменять значение.
Протестировано с Firefox 2, 3, 3.6, 4, Iron 8, Chrome 10, 12, Opera 11, Safari 5, IE 6, 9.
JavaScript ES6 (повторно) представил const
Ключевое слово, которое поддерживается во всех основных браузерах.
Переменные, объявленные через
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
декларации в любом случае, так что просто положитесь на это.
Улучшенная версия ответа Бёрка, которая позволяет вам делать CONFIG.MY_CONST
вместо CONFIG.get('MY_CONST')
,
Требуется IE9+ или настоящий веб-браузер.
var CONFIG = (function() {
var constants = {
'MY_CONST': 1,
'ANOTHER_CONST': 2
};
var result = {};
for (var n in constants)
if (constants.hasOwnProperty(n))
Object.defineProperty(result, n, { value: constants[n] });
return result;
}());
* Свойства доступны только для чтения, только если начальные значения неизменны.
Если это стоит упомянуть, вы можете определить константы в угловых, используя $provide.constant()
angularApp.constant('YOUR_CONSTANT', 'value');
В JavaScript моя практика состояла в том, чтобы как можно больше избегать констант и использовать вместо них строки. Проблемы с константами появляются, когда вы хотите представить свои константы внешнему миру:
Например, можно реализовать следующий API даты:
date.add(5, MyModule.Date.DAY).add(12, MyModule.Date.HOUR)
Но гораздо короче и естественнее просто написать:
date.add(5, "days").add(12, "hours")
Таким образом, "дни" и "часы" действительно действуют как константы, потому что вы не можете изменить извне, сколько секунд представляют "часы". Но это легко переписать MyModule.Date.HOUR
,
Такой подход также поможет в отладке. Если Firebug скажет вам action === 18
довольно сложно понять, что это значит, но когда видишь action === "save"
тогда сразу понятно.
Другой альтернативой является что-то вроде:
var constants = {
MY_CONSTANT : "myconstant",
SOMETHING_ELSE : 123
}
, constantMap = new function ConstantMap() {};
for(var c in constants) {
!function(cKey) {
Object.defineProperty(constantMap, cKey, {
enumerable : true,
get : function(name) { return constants[cKey]; }
})
}(c);
}
Тогда просто: var foo = constantMap.MY_CONSTANT
Если бы вы были constantMap.MY_CONSTANT = "bar"
это не будет иметь никакого эффекта, так как мы пытаемся использовать оператор присваивания с геттером, следовательно constantMap.MY_CONSTANT === "myconstant"
останется правдой.
Ключевое слово "const" было предложено ранее, и теперь оно официально включено в ES6. Используя ключевое слово const, вы можете передать значение / строку, которая будет действовать как неизменяемая строка.
В Javascript уже существуют константы. Вы определяете постоянную как это:
const name1 = value;
Это не может измениться путем переназначения.
Rhino.js
инвентарь const
в дополнение к тому, что было упомянуто выше.
Введение констант в JavaScript - в лучшем случае взлом.
Хорошим способом создания постоянных и глобально доступных значений в JavaScript было бы объявление литерала объекта с некоторыми свойствами "только для чтения", такими как это:
my={get constant1(){return "constant 1"},
get constant2(){return "constant 2"},
get constant3(){return "constant 3"},
get constantN(){return "constant N"}
}
все ваши константы будут сгруппированы в один "вспомогательный" объект my, где вы сможете искать свои сохраненные значения или что-либо еще, что вы, возможно, решили поместить туда по этому вопросу. Теперь давайте проверим, работает ли он:
my.constant1; >> "constant 1"
my.constant1 = "new constant 1";
my.constant1; >> "constant 1"
Как мы видим, свойство my.constant1 сохранило свое первоначальное значение. Вы сделали себе хорошие "зеленые" временные константы...
Но, конечно, это только защитит вас от случайного изменения, изменения, обнуления или очистки значения константы вашего свойства с прямым доступом, как в данном примере.
В противном случае я все еще думаю, что константы для чайников. И я все еще думаю, что обмен вашей великой свободы на маленький уголок обманчивой безопасности - худшая возможная сделка.