Czy w JavaScript są stałe?

1132

Czy istnieje sposób na użycie stałych w JavaScript ?

Jeśli nie, jaka jest powszechna praktyka określania zmiennych, które są używane jako stałe?

fuentesjr
źródło
35
Chromepozwala używać słowa kluczowego constdo używania stałych. np const ASDF = "asdf". Ponieważ jednak constnie jest kompatybilny z wieloma przeglądarkami, zwykle trzymam się vardeklaracji.
Jacksonkr,
20
try{const thing=1091;}catch(e){var thing=1091;}Pracuje.
Derek 朕 會 功夫
13
Derek: czy twoja próba / catch nie ograniczy zakresu przedmiotu, który deklarujesz do bloku try / catch? Jeśli nie masz właściwego zakresu, to po co to określać, constczy varw ogóle?
Coderer
8
@Coderer w bieżących implementacjach, to zadziała, ponieważ constma taki sam zakres jak vari to jest na poziomie funkcji, a nie na poziomie bloku. Jeśli zamiast tego postępujesz zgodnie z nadchodzącym standardem ECMAScript, constma on taki sam zakres let, co oznacza, że ​​nie będzie działać.
Jasper
3
@Coderer Niewłaściwy język. Zmienne w javascript są zakresem funkcji. To nie jest C.
doug65536

Odpowiedzi:

1018

Od wersji ES2015 JavaScript ma pojęcie const:

const MY_CONSTANT = "some-value";

Będzie to działać prawie we wszystkich przeglądarkach oprócz IE 8, 9 i 10 . Niektóre mogą również wymagać włączenia trybu ścisłego .

Możesz używać varkonwencji takich jak ALL_CAPS, aby pokazać, że niektóre wartości nie powinny być modyfikowane, jeśli potrzebujesz obsługi starszych przeglądarek lub pracujesz ze starszym kodem:

var MY_CONSTANT = "some-value";
John Millikin
źródło
60
Co powiesz na const x = 24;
Zachary Scott
93
Pamiętaj, że jeśli nie potrzebujesz kompatybilności z różnymi przeglądarkami (lub programujesz po stronie serwera w Rhino lub Node.js), możesz użyć constsłowa kluczowego. Jest obecnie obsługiwany przez wszystkie nowoczesne przeglądarki oprócz IE.
Husky
17
Obecnie (3,5 roku później) możesz używać Object.definePropertydo tworzenia właściwości tylko do odczytu, których również nie można usunąć. Działa to w bieżącej wersji wszystkich głównych przeglądarek (ale niepoprawnie w IE8 ). Zobacz odpowiedź @NotAName
Phrogz
12
@Amyth To nie jest naprawdę pomocne. To przewodnik po stylu zaproponowany przez jednego sprzedawcę. Zgodnie z powyższym punktem Husky'ego, kompatybilność z IE jest całkowicie nieistotna podczas pisania JS po stronie serwera.
aendrew
32
Ponieważ w 2015 r. Google nadal wysoko ocenia tę odpowiedź, należy powiedzieć, że jest ona obecnie nieaktualna. Słowo constkluczowe jest teraz oficjalnie częścią języka i jest obsługiwane przez każdą przeglądarkę. Według statcounter.com tylko kilka procent internautów nadal korzysta ze starych wersji przeglądarki, które nie były obsługiwane const.
Tristan
310

Czy próbujesz zabezpieczyć zmienne przed modyfikacją? Jeśli tak, możesz użyć wzorca modułu:

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

Przy takim podejściu wartości nie mogą być modyfikowane. Ale musisz użyć metody get () na CONFIG :(.

Jeśli nie musisz ściśle chronić wartości zmiennych, postępuj zgodnie z sugestią i stosuj konwencję WSZYSTKICH KAPS.

Burke
źródło
13
Zauważ, że możesz po prostu zwrócić funkcję dla wartości CONFIG. Oszczędzałoby to ciągłego wywoływania CONFIG.get ().
Mathew Byrne,
4
Ładne rozwiązanie. Ale takie rzeczy powinny być zapakowane jako biblioteka, aby nie wymyślać ich na nowo w żadnym nowym projekcie.
andrii
82
CONFIG.get = someNewFunctionThatBreaksTheCode... Podsumowując, absolutnie nie można wymuszać stałych w JS (bez słowa kluczowego const). Jedyne, co możesz zrobić, to ograniczyć widoczność.
Thomas Eding,
28
Wierzę, że privatejest to zastrzeżone słowo na przyszłość w JavaScript, nie użyłbym tego, gdybym był tobą.
Zaq
Jest to również wzorzec rejestru.
122

Słowo constkluczowe znajduje się w wersji roboczej ECMAScript 6, ale jak dotąd cieszy się tylko odrobiną obsługi przeglądarki: http://kangax.github.io/compat-table/es6/ . Składnia jest następująca:

const CONSTANT_NAME = 0;
Bill jaszczurka
źródło
13
Jeśli spróbujesz przypisać wartość do const, nie spowoduje to żadnych błędów. Przypisanie po prostu kończy się niepowodzeniem, a stała wciąż ma swoją pierwotną wartość. Jest to poważna wada projektowa IMHO, ale dopóki istnieje jasna, spójna konwencja nazewnictwa (taka jak popularna ALL_CAPS), nie sądzę, że spowodowałaby to zbyt wiele smutku.
MatrixFrog,
6
Miej oko na obsługę przeglądarki tutaj: kangax.github.io/es5-compat-table/es6/#const
Mark McDonald
6
Przypisanie @MatrixFrog spowoduje błąd 'use strict'.
sam
Czy powinienem definiować stałe w ALL CAPS?
Lewis,
1
@Tresdin Powszechną konwencją nazewnictwa jest definiowanie stałych we wszystkich wielkich literach. Nic w specyfikacji języka tego nie wymusza, ale nie jest to zły pomysł. Ułatwia to zrozumienie twoich intencji, a więc poprawia czytelność kodu.
Bill the Lizard
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

Zobacz Object.freeze . Możesz użyć,const jeśli chcesz, aby constantsodwołanie było również tylko do odczytu.

sam
źródło
2
Należy wspomnieć, że działa to tylko na IE9 + kangax.github.io/compat-table/es5 .
Cordle
Zrobiłbym to, gdyby nie miał zepsutej implementacjii
Alnitak
Uwaga: działa to podobnie do constdeklaracji ES6 , np. Właściwości nie można ponownie zadeklarować ani ponownie przypisać, ale jeśli są one typu danych object, można je mutować.
le_m
Dokładnie tego szukałem. Możesz także użyć const constantszamiast, var constantsaby zapobiec zmianie przypisania zmiennej.
Jarett Millard
Zobacz np. Głębokie zamrażanie w przypadku cyklicznego zamrażania.
sam
64

IE obsługuje stałe, takie jak np .:

<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
źródło
50
Chłopcze, mów o czymś, co nie jest przeglądarką. . . Nadal +1 za trochę nieszablonowe myślenie.
Tom
14
VBScript? Co to jest? ;)
tybro0103
2
Zwykle głosuję w dół na ogólne powiązane pytanie dotyczące różnych przeglądarek, z odpowiedzią specyficzną dla IE. Ponieważ nienawidzę ludzi, którzy uważają, że implementacja IE javascript to „One”, a innych należy po prostu zignorować. Kto używa innych przeglądarek niż IE, btw?
Ant
@Cooluhuru ten skrypt wydaje się obsługiwać zarówno przeglądarki IE (przy użyciu VBScript), jak i przeglądarki inne niż IE (przy użyciu JavaScript const). Czy możesz wyjaśnić, co jest z tym nie tak?
Andrew Grimm,
Nadal trudno mi zaakceptować możliwość zmiany stałych.
Norbert Norbertson
59

ECMAScript 5 wprowadza Object.defineProperty:

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

Jest obsługiwany w każdej nowoczesnej przeglądarce (a także IE ≥ 9).

Zobacz także: Object.defineProperty w ES5?

To nie jest imię
źródło
1
Warto zauważyć, że nie jest to tradycyjna stała. Umożliwi to tylko zdefiniowanie stałej właściwości (obiektu niestałego). Nie generuje to również błędu, a nawet zwraca wartość, którą próbujesz ustawić. Po prostu nie zapisuje wartości.
Cory Gross
3
Niedawno przeczytałem, że próba przypisania do właściwości za pomocą writable: false spowoduje błąd, jeśli kod wykonujący przypisanie jest interpretowany w trybie ścisłym ECMAScript 5. To kolejny powód, dla którego warto pisać 'use strict'w swoim kodzie.
Cory Gross
6
Możesz faktycznie pominąć, writable: falseponieważ jest to ustawienie domyślne .
sam
24

Nie, ogólnie nie. Firefox implementuje, constale wiem, że IE nie.


@John wskazuje na powszechną praktykę nazewnictwa stałych, która była używana od lat w innych językach, nie widzę powodu, dla którego nie mogłeś tego użyć. Oczywiście nie oznacza to, że ktoś i tak nie napisze wartości zmiennej. :)

Jason Bunting
źródło
11
Jak wszyscy wiedzą, jeśli IE tego nie zaimplementuje, równie dobrze może nie istnieć.
Josh Hinman
3
Niestety i praktycznie - to prawda. IE ma ogromny udział w rynku. Gdybym był właścicielem firmy i korzystałem z aplikacji internetowych wewnętrznie, ustandaryzowałbym się na FF. Nie wiem, dlaczego tak wielu ludzi obchodzi IE, wieje.
Jason Bunting
@Rich: Kto powiedział, że moja opinia jest faktem? Zrobiłeś całkiem założenie. Poza tym, o ile mi wiadomo, fakt, że IE jest do kitu jest faktem. Możesz mieć własne fakty, nie powiedziałem, że musisz uwierzyć w moje. : P Weź Xanax czy coś ...
Jason Bunting
@Rich B, tak, to był tylko głupi komentarz do złożenia i zaufaj mi, wiedziałbym, że robię wiele głupich komentarzy. @Jason B. - ciekawe, wpadłem na ten bardzo wczoraj problem. Const pracował w FF, ale nie w IE. Dzięki za wyjaśnienie
Kogo obchodzi IE? Ja nie! FF, Chrome lub Opera itp. Można zainstalować prawie na każdej platformie systemu operacyjnego. Także sprzedawcy komputerów zwykle wiedzą, że stara wersja IE jest do bani, więc często (lub nawet za każdym razem) instalują alternatywne przeglądarki przed sprzedażą komputera. Zdecydowałem więc, że mojej opracowanej aplikacji nie zależy w ogóle na niekompatybilnych przeglądarkach: jeśli twórcy przeglądarek dbają o przestrzeganie standardów, ich produkty mogą korzystać z mojej aplikacji, jeśli nie, użytkownicy będą używać innej przeglądarki ... Mogę z nią żyć; -) Ale czy Microsoft może żyć, tracąc część rynku? Nie, nie mogą, więc „Oni” zmienią swoją twórczość polityczną!
willy wonka
20

W JavaScript wolę używać funkcji do zwracania stałych wartości.

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


alert(MY_CONSTANT());
MTS
źródło
6
Warto zauważyć, że dotyczy to tego samego problemu, o którym mowa w odpowiedzi @Burkes (komentarz @ Trinithis). `MY_CONSTANT = function () {return" some-other-value "; } psuje to. +1, przyzwoite i szybkie rozwiązanie.
Patrick M,
13
-1. Nie ma to żadnej przewagi nad var SOME_NAME = wartość (wciąż jest zmienna), jest więcej kodu i wymaga wyjaśnienia.
mikemaccana
@PatrickM, chociaż prawdą jest, że możesz modyfikować tego rodzaju pseudo-stałe, w innych językach, takich jak np. C, na których nie powinieneś być w stanie modyfikować stałych, nadal możesz to robić za pomocą np. Wskaźników. Tak długo, jak zastosujesz jakieś podejście, które przynajmniej sugeruje , że jest stałe, jest w porządku imo.
rev
20

Dokumenty sieciowe Mozillas MDN zawierają dobre przykłady i wyjaśnienia const. Fragment:

// 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;

Smutne jest jednak to, że IE9 / 10 nadal nie obsługuje const. A powodem tego jest absurd :

Co więc robi IE9 z const? Do tej pory naszą decyzją było nie popierać tego. Nie jest to jeszcze funkcja konsensusu, ponieważ nigdy nie była dostępna we wszystkich przeglądarkach.

...

Ostatecznie wydaje się, że najlepszym długoterminowym rozwiązaniem dla Internetu jest pominięcie go i poczekanie na zakończenie procesów normalizacyjnych.

Nie implementują go, ponieważ inne przeglądarki nie implementowały go poprawnie ?! Zbyt boisz się, że będzie lepiej? Definicje standardów czy nie, stała jest stałą: ustawiana raz, nigdy nie zmieniana.

I do wszystkich pomysłów: każdą funkcję można zastąpić (XSS itp.). Więc nie ma różnicy w varlub function(){return}. constjest jedyną prawdziwą stałą.

Aktualizacja: IE11 obsługuje const :

IE11 obsługuje dobrze zdefiniowane i powszechnie używanych funkcji standardu powstającego ECMAScript 6, w tym Pozwolić, const, Map, Seti WeakMap, jak również __proto__do poprawy współdziałania.

mgutt
źródło
25
„nigdy nie był dostępny we wszystkich przeglądarkach”. Jeśli nie udostępnisz go w IE, to nigdy nie będzie dostępny we wszystkich przeglądarkach.
km1
normalizacja jazdy nie jest dla wszystkich;) - firmy przychodzą i odchodzą - dziękuję za zacytowanie szans w lesie
Quicker
jeszcze jedno: VBA nie jest jeszcze funkcją konsesusową we wszystkich przeglądarkach, a MS obsługuje const w VBA - jest to mistrzostwo w budowaniu budżetów programistycznych;)
Quicker
17

Jeśli nie masz nic przeciwko korzystaniu z funkcji:

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

Takie podejście oferuje funkcje zamiast zwykłych zmiennych, ale gwarantuje *, że nikt nie może zmienić wartości po jej ustawieniu.

a = constant(10);

a(); // 10

b = constant(20);

b(); // 20

Osobiście uważam to raczej za przyjemne, szczególnie po przyzwyczajeniu się do tego wzoru z nokautowych obserwowalności.

* Chyba że ktoś przedefiniował funkcję constantprzed jej wywołaniem

hasen
źródło
1
underscore.js implementuje stałą funkcję identyczną z tym kodem.
Upperstage
Prosty, zwięzły i odpowiada duchowi pytania OP. To powinno było otrzymać więcej upVotes.
Mac
3
To nigdy tak naprawdę nie działało dla mnie. Mimo że zamknięcie sprawia, że ​​jest niezmienne, zmienna, do której ją przypisujesz, może zostać zastąpiona. Np .: a = constant(10); a(10); // 10po nim a = constant(25); a(); //25nie podano żadnych błędów ani ostrzeżeń, brak wskazania, że ​​stała została zerwana.
Patrick M,
Jeśli zmienię przypisanie wartości, awówczas zmieni się ona na nową wartość
Saurabh Sharma
17

dzięki „nowemu” obiektowemu interfejsowi API możesz zrobić coś takiego:

var obj = {};
Object.defineProperty(obj, 'CONSTANT', {
  configurable: false
  enumerable: true,
  writable: false,
  value: "your constant value"
});

spójrz na to w Mozilla MDN, aby uzyskać więcej szczegółów. Nie jest to zmienna pierwszego poziomu, ponieważ jest dołączona do obiektu, ale jeśli masz zakres, cokolwiek, możesz do niego dołączyć. thispowinien również działać. Na przykład zrobienie tego w zakresie globalnym zadeklaruje pseudo-stałą wartość w oknie (co jest naprawdę złym pomysłem, nie należy beztrosko deklarować globalnych zmiennych)

Object.defineProperty(this, 'constant', {
  enumerable: true, 
  writable: false, 
  value: 7, 
  configurable: false
});

> constant
=> 7
> constant = 5
=> 7

Uwaga: przypisanie zwróci ci przypisaną wartość w konsoli, ale wartość zmiennej się nie zmieni

tenshou
źródło
Nie działa w safari i w Mozilli, jeśli ponownie wykonasz polecenie defin - z inną wartością - spowoduje to ponowne przypisanie wartości.
Akshay,
2
Nie „nie działa w safari”, nie jest obsługiwane w safari. Nie ten sam. I powinien rzucić „Uncaught TypeError: Cannot redefine property: <nazwa właściwości tutaj>”, jeśli spróbujesz tego. albo robisz to źle, albo twój ff zaimplementował to niepoprawnie. Myślę, że to połączenie obu.
tenshou
14

Grupuj stałe w struktury tam, gdzie to możliwe:

Przykład: w moim obecnym projekcie gry wykorzystałem poniżej:

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

Zadanie:

var wildType = CONST_WILD_TYPES.REGULAR;

Porównanie:

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

Ostatnio używam do porównania:

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

IE11 ma nowy standard ES6, który ma deklarację „const”.
Powyższe działa we wcześniejszych przeglądarkach takich jak IE8, IE9 i IE10.

Manohar Reddy Poreddy
źródło
12

Możesz łatwo wyposażyć skrypt w mechanizm stałych, które można ustawiać, ale nie zmieniać. Próba ich zmiany spowoduje błąd.

/* 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  
Keith
źródło
12

Zapomnij o IE i użyj constsłowa kluczowego.

Derek 朕 會 功夫
źródło
9
pracuje dla mnie! ale potem piszę chromowane rozszerzenie, więc wiem, że korzystam z rozsądnej przeglądarki ...
yoyo
1
@yoyo najlepsza część na temat pisania rozszerzeń i dodatków - brak obsługi w różnych przeglądarkach!
Ian
1
@Ian Witamy w 2019 r., Niespójność między przeglądarkami prawie zniknęła :)
Fusseldieb
9

Jednak nie ma dokładnie określonego sposobu, aby to zrobić w różnych przeglądarkach, można to osiągnąć, kontrolując zakres zmiennych, jak pokazano w innych odpowiedziach.

Ale zasugeruję użycie przestrzeni nazw w celu odróżnienia od innych zmiennych. zmniejszy to do minimum prawdopodobieństwo kolizji z innymi zmiennymi.

Właściwa przestrzeń nazw jak

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

więc podczas korzystania będzie iw_constant.namelubiw_constant.age

Możesz także zablokować dodawanie nowego klucza lub zmianę dowolnego klucza wewnątrz iw_constant przy użyciu metody Object.freeze. Jednak nie jest obsługiwany w starszej przeglądarce.

dawny:

Object.freeze(iw_constant);

W starszych przeglądarkach można użyć metody polyfill do zamrożenia.


Jeśli nie masz nic przeciwko funkcji wywoływania, najlepszym sposobem zdefiniowania stałej jest najlepsza przeglądarka internetowa. Określanie zakresu obiektu w ramach funkcji wykonującej się samoczynnie i zwracanie funkcji get dla stałych np.

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

       };

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

// aby uzyskać wartość użyj iw_constant('name')lubiw_constant('age')


** W obu przykładach należy bardzo uważać na odstępy między nazwami, aby nie zastąpić obiektu lub funkcji inną biblioteką (jeśli sam obiekt lub funkcja zostaną zastąpione, cała stała zostanie zmieniona)

Sudhanshu Yadav
źródło
7

Przez jakiś czas podałem „stałe” (które wciąż nie były stałymi) w literałach obiektowych przekazywanych do with()instrukcji. Myślałem, że to takie sprytne. Oto przykład:

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

W przeszłości utworzyłem również CONSTprzestrzeń nazw, w której umieściłem wszystkie moje stałe. Ponownie, z kosztami ogólnymi. Do licha.

Teraz, po prostu zrobić var MY_CONST = 'whatever';na KISS .

Andrew Hedges
źródło
16
Jeśli jest coś bardziej złego niż ewaluacja, to na pewno with.
NikiC
4
eval jest bardzo zły! Pewnego razu spłonął mój dom!
W3Geek
6

Moja opinia (działa tylko z obiektami).

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

Próbować! Ale zrozum - to obiekt, ale nie prosta zmienna.

Spróbuj także:

const a = 9;
użytkownik1635543
źródło
5

Ja też miałem z tym problem. Po dłuższej chwili szukania odpowiedzi i analizowania wszystkich odpowiedzi wydaje mi się, że znalazłem realne rozwiązanie tego problemu.

Wygląda na to, że większość odpowiedzi, na które natrafiłem, wykorzystuje funkcje do przechowywania stałych. Jak wielu użytkowników forów WIELU forów pisze, funkcje mogą być łatwo nadpisane przez użytkowników po stronie klienta. Zaintrygowała mnie odpowiedź Keitha Evettsa, że ​​do obiektu stałych nie można uzyskać dostępu z zewnątrz, ale tylko z funkcji wewnątrz.

Wymyśliłem więc to rozwiązanie:

Umieść wszystko w anonimowej funkcji, aby zmienne, obiekty itp. Nie mogły zostać zmienione po stronie klienta. Ukryj także „rzeczywiste” funkcje, ponieważ inne funkcje wywołują „rzeczywiste” funkcje od wewnątrz. Pomyślałem także o użyciu funkcji do sprawdzenia, czy funkcja została zmieniona przez użytkownika po stronie klienta. Jeśli funkcje zostały zmienione, zmień je z powrotem za pomocą zmiennych, które są „chronione” wewnątrz i nie można ich zmienić.

/*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);
  };
}())

Wydaje się również, że bezpieczeństwo jest naprawdę problemem i nie ma sposobu, aby „ukryć” swoje programowanie po stronie klienta. Dobrym pomysłem jest dla mnie skompresowanie twojego kodu, aby naprawdę trudno było go przeczytać i zrozumieć każdemu, włączając ciebie, programistę. Istnieje strona, na którą możesz przejść: http://javascriptcompressor.com/ . (To nie jest moja strona, nie martw się, nie reklamuję się.) To jest strona, która pozwoli ci kompresować i zaciemniać kod JavaScript za darmo.

  1. Skopiuj cały kod z powyższego skryptu i wklej go do górnego obszaru tekstowego na stronie javascriptcompressor.com.
  2. Zaznacz pole wyboru Kodowanie Base62, zaznacz pole wyboru Zmienne skurczowe.
  3. Naciśnij przycisk Kompresuj.
  4. Wklej i zapisz wszystko w pliku .js i dodaj go do swojej strony w nagłówku strony.
Steven Kapaun
źródło
To dobre rozwiązanie, które można ładnie zapakować jako bibliotekę. Ale nie lubię nazywania twoich zmiennych w tym kodzie. Po co upuszczać opisowe nazwy, takie jak „nazwa” i „wartość”, tak jak zostały użyte w kodzie Keitha? Drobny problem, ale nadal.
Cordle
5

Wyraźnie pokazuje to potrzebę znormalizowanego słowa kluczowego const dla różnych przeglądarek.

Ale teraz:

var myconst = value;

lub

Object['myconst'] = value;

Oba wydają się wystarczające, a wszystko inne przypomina strzelanie do muchy za pomocą bazooki.

codemuncher
źródło
weź stary dobry var myconst = wartość; a do debugowania użyj dodatkowego kodu debugowania ... - działa jak szalony, o ile nie wszystkie przeglądarki obsługują const
Quicker
4

Używam constzamiast varw moich skryptach Greasemonkey, ale
dzieje się tak dlatego, że będą działały tylko w przeglądarce Firefox ... Konwencja nazw może być naprawdę dobrym rozwiązaniem (robię oba!).

PhiLho
źródło
4

W JavaScripcie moją praktyką było unikanie stałych w jak największym stopniu i zamiast tego używanie ciągów. Problemy ze stałymi pojawiają się, gdy chcesz wystawić swoje stałe na świat zewnętrzny:

Na przykład można zaimplementować następujący interfejs API Data:

date.add(5, MyModule.Date.DAY).add(12, MyModule.Date.HOUR)

Ale o wiele krótsze i bardziej naturalne jest napisanie:

date.add(5, "days").add(12, "hours")

W ten sposób „dni” i „godziny” naprawdę działają jak stałe, ponieważ nie można zmienić z zewnątrz, ile sekund reprezentuje „godzina”. Ale łatwo go zastąpić MyModule.Date.HOUR.

Takie podejście pomoże również w debugowaniu. Jeśli Firebug powie Ci, action === 18że ciężko jest zrozumieć, co to znaczy, ale kiedy zobaczysz action === "save", natychmiast będzie jasne.

Rene Saarsoo
źródło
Niestety błędy w pisowni są dość łatwe - np. "Hours"Zamiast "hours"- ale IDE może wcześnie dać ci znać, że Date.Hoursnie jest zdefiniowane.
le_m,
4

Okej, to jest brzydkie, ale daje mi stałą w Firefoksie i Chromium, niestałą stałą (WTF?) W Safari i Operze oraz zmienną w IE.

Oczywiście eval () jest złem, ale bez niego IE generuje błąd, uniemożliwiając uruchamianie skryptów.

Safari i Opera obsługują słowo kluczowe const, ale można zmienić jego wartość .

W tym przykładzie kod po stronie serwera zapisuje JavaScript na stronie, zastępując {0} wartością.

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

Do czego to służy? Niewiele, ponieważ nie jest to przeglądarka. W najlepszym razie może trochę spokoju, że przynajmniej niektóre przeglądarki nie pozwalają bookmarkletom ani skryptowi innej firmy modyfikować wartość.

Testowane z Firefox 2, 3, 3.6, 4, Iron 8, Chrome 10, 12, Opera 11, Safari 5, IE 6, 9.

Webveloper
źródło
1
Uwielbiam ten kod! Brzydkie jak cholera, ale dobry test na stałe wsparcie. =)
Stein G. Strindhaug,
1
nieco zabawne, ey ​​- ile linii można wpisać, aby zadeklarować stałą?
Szybszy
4

Jeśli warto wspomnieć, można zdefiniować stałe za pomocą kątownika$provide.constant()

angularApp.constant('YOUR_CONSTANT', 'value');
Muhammad Reda
źródło
... i możesz użyć const w VBA ... xbrowser? ... ups ...;)
Quicker
OP pyta o javascript, odpowiedź dotyczy konkretnych mocno opiniotwórczych ram JS. Praktycznie nie na temat.
rounce
2
@rounce: odpowiedzi Off-topic jeszcze odpowiedzi, nie Oznacz je jako nie odpowiedzi , ale downvote i głosowanie usunąć zamiast. Zobacz Jak prawidłowo używać flagi „Brak odpowiedzi”?
Kevin Guan,
@KevinGuan Noted, zrobi to w przyszłości.
rounce
4

Ulepszona wersja odpowiedzi Burke'a, która na to pozwalaCONFIG.MY_CONST zamiast CONFIG.get('MY_CONST').

Wymaga IE9 + lub prawdziwej przeglądarki internetowej.

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

* Właściwości są tylko do odczytu, tylko jeśli wartości początkowe są niezmienne.

Şafak Gür
źródło
4

JavaScript ES6 (ponownie) wprowadził constsłowo kluczowe, które jest obsługiwane we wszystkich głównych przeglądarkach .

Zmienne zadeklarowane przez constnie mogą być ponownie zadeklarowane ani ponownie przypisane.

Poza tym constzachowuje się podobnie do let.

Zachowuje się zgodnie z oczekiwaniami dla prymitywnych typów danych (logiczna, zerowa, niezdefiniowana, liczba, łańcuch, symbol):

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

Uwaga: należy pamiętać o pułapkach związanych z obiektami:

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

Jeśli naprawdę potrzebujesz niezmiennego i absolutnie stałego obiektu: po prostu użyj, const ALL_CAPSaby wyrazić swoją intencję. Jest to dobra konwencja do przestrzegania wszystkich constdeklaracji, więc polegaj na niej.

le_m
źródło
Od IE11 tylko :-(
Mo.
3

Inną alternatywą jest coś takiego:

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

Następnie po prostu: var foo = constantMap.MY_CONSTANT

Gdybyś constantMap.MY_CONSTANT = "bar"to zrobił, nie przyniosłoby to żadnego efektu, ponieważ próbujemy użyć operatora przypisania z modułem pobierającym, dlatego constantMap.MY_CONSTANT === "myconstant"pozostałoby to prawdą.

rozerwać
źródło
3

w Javascript już istnieją stałe . Definiujesz stałą w ten sposób:

const name1 = value;

Nie można tego zmienić poprzez zmianę przypisania.

Erik Lucio
źródło
Według linku w odpowiedzi jest to funkcja eksperymentalna i powinna być używana ostrożnie.
Johnie Karr,
Oczywiście zgadzam się z tobą. Ale w ostatnich wersjach przeglądarek Działa.
Erik Lucio
3

Słowo kluczowe „const” zostało zaproponowane wcześniej i teraz zostało oficjalnie włączone do ES6. Używając słowa kluczowego const, możesz przekazać wartość / ciąg znaków, który będzie działał jako ciąg niezmienny.

Ritumoni Sharma
źródło
2

Wprowadzenie stałych do JavaScript to w najlepszym wypadku hack.

Dobrym sposobem tworzenia trwałych i globalnie dostępnych wartości w JavaScript byłoby zadeklarowanie literału obiektu z pewnymi właściwościami „tylko do odczytu”, takimi jak:

            my={get constant1(){return "constant 1"},
                get constant2(){return "constant 2"},
                get constant3(){return "constant 3"},
                get constantN(){return "constant N"}
                }

będziesz mieć wszystkie swoje stałe zgrupowane w jednym „dodatkowym” obiekcie pomocniczym, w którym możesz szukać przechowywanych wartości lub czegokolwiek innego, co mógłbyś tam umieścić w tym celu. Teraz sprawdźmy, czy to działa:

           my.constant1; >> "constant 1" 
           my.constant1 = "new constant 1";
           my.constant1; >> "constant 1" 

Jak widać, właściwość „my.constant1” zachowała swoją pierwotną wartość. Zrobiłeś sobie miłe „zielone” stałe tymczasowe ...

Ale to oczywiście ochroni cię tylko przed przypadkową modyfikacją, zmianą, unieważnieniem lub opróżnieniem stałej wartości nieruchomości z bezpośrednim dostępem, jak w podanym przykładzie.

W przeciwnym razie nadal uważam, że stałe są dla manekinów. Nadal uważam, że wymiana waszej wielkiej wolności na mały kłamstwo oszukańczego bezpieczeństwa to najgorszy możliwy handel.

Bill jaszczurka
źródło
2

Rhino.jswdraża constoprócz tego, co wspomniano powyżej.

izomorfizmy
źródło