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

1133

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

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

fuentesjr
источник
35
Chromeпозволяет использовать ключевое слово constдля использования констант. например const ASDF = "asdf". Однако, поскольку constон не совместим с несколькими браузерами, я обычно придерживаюсь varдекларации.
Джексонкр
20
try{const thing=1091;}catch(e){var thing=1091;}работает.
Дерек 功夫 會 功夫
13
Дерек: разве ваш try / catch не ограничивает область действия того, что вы объявляете блоком try / catch? Если вы неправильно определяете область, то какой смысл указывать constили varвообще?
Coderer
8
@Coderer в текущих реализациях, это будет работать, так как constимеет ту же область видимости var, что и уровень функции, а не уровень блока. Если вы будете следовать следующему стандарту ECMAScript, он будет constиметь ту же область действия let, что означает, что он не будет работать.
Джаспер
3
@ Кодер Неправильный язык. Переменные в javascript являются областью действия функции. Это не C.
doug65536

Ответы:

1019

Начиная с ES2015 , JavaScript имеет понятие const:

const MY_CONSTANT = "some-value";

Это будет работать практически во всех браузерах, кроме IE 8, 9 и 10 . Некоторым также может потребоваться строгий режим .

Вы можете использовать varс соглашениями, такими как ALL_CAPS, чтобы показать, что определенные значения не должны быть изменены, если вам нужно поддерживать старые браузеры или работать с устаревшим кодом:

var MY_CONSTANT = "some-value";
Джон Милликин
источник
60
Как насчет const x = 24;
Захари Скотт
93
Обратите внимание, что если вам не нужна кросс-браузерная совместимость (или вы программируете на стороне сервера на Rhino или Node.js), вы можете использовать constключевое слово. В настоящее время поддерживается всеми современными браузерами, кроме IE.
Husky
17
В эти дни (3,5 года спустя) вы можете использовать Object.definePropertyдля создания свойств только для чтения, которые также не могут быть удалены. Это работает в текущей версии всех основных браузеров (но неправильно в IE8 ). Смотрите ответ @NotAName
Phrogz
12
@ Амит Это не очень полезно. Это руководство по стилю, предлагаемое единственным поставщиком. Как указано выше в статье Хаски, совместимость с IE совершенно не имеет значения при написании JS на стороне сервера.
конец
32
Поскольку этот ответ по-прежнему высоко оценивается Google в 2015 году, следует сказать, что в настоящее время он устарел. constКлючевое слово теперь официально является частью языка и поддерживается каждым браузером. По данным statcounter.com, лишь несколько процентов интернет-пользователей все еще используют старые версии браузеров, которые не поддерживают const.
Тристан
310

Вы пытаетесь защитить переменные от модификации? Если это так, то вы можете использовать шаблон модуля:

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.

замять
источник
13
Обратите внимание, что вы можете просто вернуть функцию для значения CONFIG. Это спасло бы вас от вызова CONFIG.get () все время.
Мэтью Бирн
4
Красивое решение. Но такие вещи должны быть обернуты как библиотека, чтобы не изобретать их в любом новом проекте.
Андрей
82
CONFIG.get = someNewFunctionThatBreaksTheCode... В общем, вы абсолютно не можете применять константы в JS (без ключевого слова const). Единственное, что вы можете сделать, это ограничить видимость.
Томас Эдинг
28
Я действительно считаю, что privateэто будущее зарезервированное слово в JavaScript, я бы не использовал его на вашем месте.
Зак
Это также шаблон реестра.
122

constКлючевое слово в проекте ECMAScript 6 , но при этом он пользуется пока только небольшим количеством поддержки браузера: http://kangax.github.io/compat-table/es6/ . Синтаксис:

const CONSTANT_NAME = 0;
Билл Ящерица
источник
13
Если вы попытаетесь присвоить значение a const, оно не выдаст никаких ошибок. Присвоение просто не выполняется, и константа все еще имеет свое первоначальное значение. Это главный недостаток дизайна IMHO, но пока существует четкое, согласованное соглашение об именах (такое как популярная ALL_CAPS), я не думаю, что это вызовет слишком много горя.
MatrixFrog
6
Следите за поддержкой браузера здесь: kangax.github.io/es5-compat-table/es6/#const
Марк Макдональд
6
@MatrixFrog назначение вызовет ошибку с 'use strict'.
Сэм
Должен ли я определить константы в ALL CAPS?
Льюис
1
@Tresdin Это общее соглашение об именах для определения констант во всех заглавных буквах. Ничто в спецификации языка не заставляет это, но это не плохая идея. Это проясняет ваши намерения и улучшает читаемость кода.
Билл Ящерица
68
"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ссылку также доступной только для чтения.

Сэм
источник
2
Следует отметить, что это работает только на IE9 + kangax.github.io/compat-table/es5 .
Кордл
Я бы, если бы не было сломанной реализацииi
Альнитак
Примечание: это ведет себя подобно constобъявлению ES6 , например, свойства не могут быть повторно объявлены или переназначены, но если они имеют тип данных object, они могут быть изменены.
le_m
Именно то, что я искал. Вы также можете использовать const constantsвместо, var constantsчтобы предотвратить переназначение переменной.
Джаретт Миллард,
См., Например, морозильник для рекурсивного замораживания.
Сэм
64

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>
C Nagle
источник
50
Мальчик, поговори о чем-то, что не является кросс-браузерным. , , Еще +1 за мысли немного нестандартно.
Том
14
VBScript? Что это такое? ;)
tybro0103
2
Я обычно голосую за общий вопрос, связанный с браузерами, с конкретным ответом IE. Потому что я ненавижу людей, которые думают, что реализация javascript в IE - это «Единый», а другие просто игнорируются. Кто использует другие браузеры, кроме IE, кстати?
Муравей
@Cooluhuru, этот скрипт, по-видимому, обрабатывает как браузеры IE (с использованием VBScript), так и браузеры без IE (с использованием JavaScript const). Можете ли вы объяснить, что с ним не так?
Эндрю Гримм
Мне все еще трудно принять, что константы могут быть изменены.
Норберт Норбертсон
59

ECMAScript 5 действительно вводит Object.defineProperty:

Object.defineProperty (window,'CONSTANT',{ value : 5, writable: false });

Он поддерживается в любом современном браузере (а также IE ≥ 9).

Смотрите также: Object.defineProperty в ES5?

Не имя
источник
1
Стоит отметить, что это не похоже на традиционную константу. Это позволит вам только определить постоянное свойство (неконстантного объекта). Также это не генерирует ошибку и даже возвращает значение, которое вы пытаетесь установить. Это просто не записывает значение.
Кори Гросс
3
Недавно я читал, что попытка присвоения свойству с помощью на самом деле writable: false вызовет ошибку, если код, выполняющий присвоение, интерпретируется в строгом режиме ECMAScript 5. Просто еще одна причина, чтобы писать 'use strict'в ваш код.
Кори Гросс
6
Вы можете на самом деле опустить, writable: falseтак как это по умолчанию .
Сэм
24

Нет не вообще. Firefox реализует, constно я знаю, что IE нет.


@Джон указывает на распространенную практику именования для conts, которая годами использовалась на других языках, и я не вижу причин, почему вы не могли бы это использовать. Конечно, это не значит, что кто-то не будет переписывать значение переменной в любом случае. :)

Джейсон Бантинг
источник
11
Как известно, если IE не реализует его, он может и не существовать.
Джош Хинман
3
К сожалению, и практически говоря - это правда. IE владеет огромной долей рынка. Если бы я владел бизнесом и имел веб-приложения для внутреннего использования, я бы стандартизировал FF. Я не знаю, почему так много людей заботятся о IE, это дует.
Джейсон Бантинг
@Rich: Кто сказал, что мое мнение было фактом? Вы сделали довольно предположение. Кроме того, насколько я понимаю, факт, что IE отстой, является фактом. Вы можете иметь свои собственные факты, я не говорил, что вы должны верить моим. : P Возьмите Xanax или что-то ...
Джейсон Бантинг
@Rich B, да, это был просто глупый комментарий, и, поверьте мне, я бы сделал много глупых комментариев. @ Джейсон Б. - интересно, я столкнулся с этой самой проблемой прошлой ночью .. const работал в FF, но не в IE. Спасибо за разъяснения
Кого волнует IE? Я не! FF или Chrome или Opera и т. Д. ... могут быть установлены практически на любой платформе ОС. Кроме того, розничные продавцы компьютеров обычно знают, что старая версия IE - отстой, поэтому они часто (или даже каждый раз) устанавливают альтернативные браузеры перед продажей компьютера. Поэтому я решил, что мое разработанное приложение не должно заботиться о несовместимых браузерах: если разработчики браузеров заботятся о соблюдении стандартов, их продукт может использовать мое приложение, если нет, пользователи будут использовать другой браузер ... Я могу жить с этим; -) Но может ли Microsoft вживую потерять часть рынка? Нет, они не могут, так что «Они» изменят свою политику разработчиков!
Вилли Вонка
20

В JavaScript я предпочитаю использовать функции для возврата постоянных значений.

function MY_CONSTANT() {
   return "some-value";
}


alert(MY_CONSTANT());
МТС
источник
6
Стоит отметить, что это относится к той же проблеме, о которой говорилось в ответе @Burkes (комментарий @trinithis). `MY_CONSTANT = function () {return" some-other-value "; } ломает это. +1 хотя, достойное и быстрое решение.
Патрик М
13
-1. Это не имеет никакого преимущества по сравнению с var SOME_NAME = value (оно все еще изменчиво), содержит больше кода и требует объяснения.
mikemaccana
@PatrickM, хотя это правда, что вы можете изменять такого рода псевдоконстанты, в других языках, таких как, например, C, для которых вы не можете изменять константы, вы все равно можете делать это, например, с помощью указателей. Так что, если вы используете какой-то подход, который, по крайней мере, предполагает, что это константа, это хорошо, imo.
Рев
20

Документы 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 , включая пусть, const, Map, Set, и WeakMap, а также __proto__для улучшения совместимости.

mgutt
источник
25
msgstr "это никогда не было доступно во всех браузерах". Если вы не сделаете это доступным в IE, то это никогда не будет во всех браузерах.
км1
Стандартизация вождения не для всех;) - компании приходят и уходят снова - спасибо за цитирование шансов в лесу
Quicker
Еще один вопрос: VBA еще не реализована во всех браузерах, а MS поддерживает const в VBA - это мастерство распределения бюджетов на разработку;)
Quicker
17

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

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

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

a = constant(10);

a(); // 10

b = constant(20);

b(); // 20

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

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

Hasen
источник
1
underscore.js реализует постоянную функцию, идентичную этому коду.
Верхний этап
Просто, лаконично и отвечает духу вопроса ОП. Это должно было получить больше голосов.
Mac
3
Это никогда не работало для меня. Несмотря на то, что замыкание делает его неизменным, переменная, которой вы его назначаете, все равно может быть перезаписана. Пример: a = constant(10); a(10); // 10за ним a = constant(25); a(); //25нет ошибок и предупреждений, нет указаний на то, что ваша константа была нарушена.
Патрик М
Если я переназначу значение, aто оно изменится на новое значение
Саурабх Шарма
17

с помощью «нового» 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

примечание: назначение вернет вам назначенное значение в консоли, но значение переменной не изменится

tenshou
источник
Не работает в сафари и в Mozilla, если вы снова выполните оператор define - с другим значением - он переназначит значение.
Акшай
2
Не «не работает в сафари», не поддерживается в сафари. Не то же самое. И он должен выдать 'Uncaught TypeError: Cannot redefine property: <имя свойства здесь>', если вы попытаетесь это сделать. либо вы делаете это неправильно, либо ваш ff неправильно это реализовал. Я предполагаю, что это смесь обоих.
Теньшоу
14

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

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

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

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

/* 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  
Кит
источник
12

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

Дерек 朕 會 功夫
источник
9
работает для меня! но потом я пишу расширение для Chrome, так что я знаю, что я в здравом браузере ...
yoyo
1
@yoyo лучшая часть о написании расширений и надстроек - без кросс-браузерной поддержки!
Ян
1
@Ian Добро пожаловать в 2019 году, кросс-браузерная несогласованность почти исчезла :)
Fusseldieb
9

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

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

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

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')


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

Судханшу Ядав
источник
7

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

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

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

Теперь, я просто var MY_CONST = 'whatever';в КИСС .

Эндрю Хеджес
источник
16
Если есть нечто более злое, чем Eval, это определенно with.
NikiC
4
Эвал очень злой! Это сгорело в моем доме один раз!
W3Geek
6

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

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;
user1635543
источник
5

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

Кажется, что большинство ответов, которые я встречал, использует функции для хранения констант. Как пишут многие пользователи форумов 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 и добавьте его на свою страницу в верхней части страницы.
Стивен Капаун
источник
Это хорошее решение, которое можно было бы включить в библиотеку. Но мне не нравится именование ваших переменных в этом коде. Зачем отбрасывать описательные имена, такие как «имя» и «значение», которые используются в коде Кейта? Незначительная проблема, но все же.
Кордл
5

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

Но сейчас:

var myconst = value;

или

Object['myconst'] = value;

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

codemuncher
источник
возьмите старый добрый var myconst = value; и для отладки используйте дополнительный код отладки ... - работает как сумасшедший, пока не все браузеры поддерживают const
Quicker
4

Я использую constвместо этого varв своих скриптах Greasemonkey, но это потому, что они будут работать только в Firefox ...
Соглашение об именах действительно может быть подходом (я делаю и то и другое!).

PhiLho
источник
4

В 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"это сразу понятно.

Рене Саарсоо
источник
К сожалению, довольно легко совершать орфографические ошибки - например, "Hours"вместо "hours"- но IDE может дать вам знать на ранней стадии, что Date.Hoursэто не определено.
le_m
4

Хорошо, это уродливо, но оно дает мне константу в 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.

Webveloper
источник
1
Люблю этот код! Ужасно, черт возьми, но хороший тест для поддержки const. =)
Стейн Г. Стриндхауг
1
несколько смешно, эй - сколько строк вы можете напечатать, чтобы объявить const?
Более быстрый
4

Если это стоит упомянуть, вы можете определить константы в угловых, используя$provide.constant()

angularApp.constant('YOUR_CONSTANT', 'value');
Мухаммед Реда
источник
... и вы можете использовать const в VBA ... xbrowser? ... ups ...;)
Quicker
OP спрашивает о javascript, ответ имеет отношение к конкретной, сильно мнительной структуре JS. Практически не по теме.
Раунс
2
@rounce: Off-Topic ответы еще ответы, не флаг им , как не ответ , но downvote и голосовать удалить вместо. См. Как правильно использовать флаг «Не ответ»?
Кевин Гуан
@KevinGuan Отмечено, будет делать в будущем.
Раунс
4

Улучшенная версия ответа Бёрка, которая позволяет вам делать 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;
}());

* Свойства доступны только для чтения, только если начальные значения неизменны.

Шафак Гюр
источник
4

В 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любом случае, это хорошее соглашение для всех деклараций, так что просто полагайтесь на него.

le_m
источник
От IE11 только :-(
Мо
3

Другой альтернативой является что-то вроде:

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"останется верным.

rounce
источник
3

в Javascript уже существуют константы . Вы определяете константу как это:

const name1 = value;

Это не может измениться путем переназначения.

Эрик Лучио
источник
По ссылке в ответе, это экспериментальная функция и должна использоваться с осторожностью.
Джони Карр
Конечно, я с тобой согласен. Но в последних версиях браузеров это работает.
Эрик Лучио
3

Ключевое слово «const» было предложено ранее, и теперь оно официально включено в ES6. Используя ключевое слово const, вы можете передать значение / строку, которая будет действовать как неизменяемая строка.

Ритумони Шарма
источник
2

Введение констант в 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 сохранило свое первоначальное значение. Вы сделали себе хорошие "зеленые" временные константы ...

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

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

Билл Ящерица
источник
2

Rhino.jsреализует constв дополнение к тому, что было упомянуто выше.

isomorphismes
источник