48

I think I know the answer but... is there any way to prevent a global variable from being modified by later-executing <script>? I know global variables are bad in the first place, but when necessary, is there a way to make it "final" or "immutable"? Hacks / creative solutions are welcome. Thanks

jtgameover
  • 1,303
  • 3
  • 13
  • 19
  • Nothing comes to mind. But I'm sure there's a better solution, if you can say what kind of problem you are trying to solve. – Vasil Mar 20 '09 at 02:54
  • 1
    just FYI, global variables are actually the properties of the window object and similary global functions are methods of the window object. – Jamol Mar 20 '09 at 13:53

15 Answers15

61

the const keyword?

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
Real Red.
  • 4,991
  • 8
  • 32
  • 44
  • 1
    why downvote? could you please give reason so that we know. I am not sure of my answer because I've never used it myself. So only I've put ques. mark in my answer. Moreover, when I tried in IE it failed. So, it'd be good if you clearify the reason for your downvote. – Real Red. Mar 20 '09 at 04:00
  • 1
    Not really sure why this got down voted, but this should work. At least, any browser that supports JS 1.5 or greater. – Steve Willard Mar 20 '09 at 04:19
  • yeah, thats what was my initial idea for posting. but then again I wasn't totally sure because I hadn't used it myself. – Real Red. Mar 20 '09 at 06:08
  • 1
    @Presario. Its a standard in JS 1.5. Just because it doesn't work in Opera doesn't prove anything. It didn't work for me in IE6 too. And in my answer I am not claiming that its gonna work. I just quoted a hyperlink which I thought may be of some help. Do you see a '?' in my answer? – Real Red. Mar 20 '09 at 13:13
  • JavaScript is Mozilla's version of ECMAScript; if you want your scipt to work across different browsers, stick to what's in ECMA-262, 3rd edition – Christoph Mar 20 '09 at 13:20
  • @Liverpool 4 - 1 Mancs. The question is not about standards, your suggestion/solution (whatever) does not work and therefore is of no use to the questioner. That's why it deserves a downvote. – Jamol Mar 20 '09 at 13:36
  • [EWD about the distinction between language definition and implementation](http://www.cs.utexas.edu/users/EWD/transcriptions/EWD04xx/EWD447.html) – Richard JP Le Guen May 12 '11 at 13:39
  • It is not really supported. I once searched for hours when a page broke in IE because of that. **You should not use `const`!** – Cedric Reichenbach Nov 02 '13 at 14:46
  • @RealRed. your answer after 6 years is starting to be relevant, but also is that const is not inmutable. check this answer about const http://programmers.stackexchange.com/a/290514/57947 – ncubica Sep 22 '15 at 07:46
  • with const you can't do something like: const x; and at some point: x = 12; so to make immutable after first initialization. – someUser Nov 01 '16 at 11:01
  • 1
    Correct me if I'm wrong but I thought `CONST` only meant that you couldn't redeclare the variable - it doens't make it immutable. e.g. you can still add items to the array using `push()` if the variable was declared as an array to start with, also using the `CONST` keyword. Again, I may have a core-misunderstanding here but this is just what I though was the case. – DevLime Feb 08 '19 at 10:28
18

I know this question is old, but you could use Object.freeze(yourGlobalObjectHere); I just wrote a blog post about it here.

iambrandonn
  • 301
  • 3
  • 3
  • Haven't tried it yet because I can't test it now. But seeing your description in your blog, I think this should be the correct answer. :) Because I want my global array to be immutable, so when I accidentally change it with some mutable function, it should warn/make an error. – Michael Harley Aug 27 '19 at 13:13
15

You can use closure technique, MYGLOBALS is an object that has a function called getValue against the "globals" associative array that is out of scope for everything except MYGLOBALS instance.

var MYGLOBALS = function() {
    var globals = {
        foo : "bar",
        batz : "blah"       
    }
    return { getValue : function(s) {
            return globals[s];
        }
    }
}();
alert(MYGLOBALS.getValue("foo"));  // returns "bar"
alert(MYGLOBALS.getValue("notthere")); // returns undefined
MYGLOBALS.globals["batz"] = 'hardeehar'; // this will throw an exception as it should
Denes Papp
  • 3,835
  • 3
  • 32
  • 33
Dan Doyon
  • 6,710
  • 2
  • 31
  • 40
  • 7
    Nice try, but they can still replace the MYGLOBALS in one goal, anyway. – Dennis C Mar 20 '09 at 04:16
  • 2
    Or replace the `getValue` property in MYGLOBALS with another function that returns different values. – Wyzard Dec 15 '09 at 04:39
  • Forget about JavaScript, The truth is, There is nothing like immutable in this world. everything changes. Change is the constant :) For JavaScript, we have to follow good practices and have knowledge of what we are doing. – Amogh Talpallikar Feb 08 '13 at 06:49
9

yes the const is short for constant or final in some languages. google "javascript variable const" or constant to double i have even tested it myself so

const yourVar = 'your value';

thats what you are looking for.

Val
  • 131
  • 1
  • 1
5
Object.defineProperty(window, 'CONSTANT_NAME', {value: CONSTANT_VALUE});

// usage
console.log(CONSTANT_NAME);

Object.defineProperty() creates a property with the following default attributes:

  • configurable true if and only if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object. Defaults to false.

  • enumerable true if and only if this property shows up during enumeration of the properties on the corresponding object. Defaults to false.

  • writable true if and only if the value associated with the property may be changed with an assignment operator. Defaults to false.

if the "constant" is an object you might additionally want to make it immutable by freezing it. obj =Object.freeze(obj). have in mind that child-property-objects are not automatically frozen.

dreamlab
  • 3,321
  • 20
  • 23
5

This would be much cleaner approach

   var CONSTANTS = function() {
        var constants = { } ; //Initialize Global Space Here
        return {
            defineConstant: function(name,value)
            {
                if(constants[name])
                {
                   throw "Redeclaration of constant Not Allowed";
                }
            },
            getValue(name)
            {
               return constants[name];
            }
        } ;
    }() ;
    CONSTANTS.defineConstant('FOO','bar') ;
    console.log(CONSTANTS.getValue('FOO')) ; //Returns bar
    CONSTANTS.defineConstant('FOO','xyz') ; // throws exception as constant already defined
    CONSTANTS.getValue('XYZ') ; //returns undefined
Naveen DA
  • 4,148
  • 4
  • 38
  • 57
serioys sam
  • 2,011
  • 1
  • 12
  • 10
4

try this:

const whatEver = 'Hello World!!!';

function foo(value){
 whatEver = value;
}

then you would call it like so...

<div onclick="foo('New Value');">Change Me First</div>
<div onclick="alert(whatEver);">Then click me After: Should Be alert "Hello World!!!"</div>
Val
  • 131
  • 1
  • 1
2

what about this code by http://ejohn.org/ @ http://ejohn.org/blog/ecmascript-5-objects-and-properties/

Look like this actually works... I run some "little" testing and freeze the variables and attributes.

Freezing an object is the ultimate form of lock-down. Once an object has been frozen it cannot be unfrozen – nor can it be tampered in any manner. This is the best way to make sure that your objects will stay exactly as you left them, indefinitely.

Object.freeze = function( obj ) {
  var props = Object.getOwnPropertyNames( obj );

  for ( var i = 0; i < props.length; i++ ) {
    var desc = Object.getOwnPropertyDescriptor( obj, props[i] );

    if ( "value" in desc ) {
      desc.writable = false;
    }

    desc.configurable = false;
    Object.defineProperty( obj, props[i], desc );
  }

  return Object.preventExtensions( obj );
};

Little example

var config = (function (__name) {
    name: __name
    var _local = {
        Server: "SomeText",
        ServerDate: "SomeServerDate",
        JSDate : Util.today(),
        User : {
            user: "1stUser",
            name: "",
            email: ""
        },        
    }

    /*Private Methods*/
    function freezing(__array) {
        $.each(__array, function (_index, _item) {
            Object.freeze(_item);
        });
    }

    /*Public Methods*/
    var $r = {};

    $r.info = function () {
        return _local;
    }

    freezing([
        _local,
        _local.User
    ]);


    _local.User.user = "newUser"; //Trying to assing new value

    //Remain with the same value as first declaration
    console.log(_local.User.user); //--> "1stUser"           
    return $r;
})("config");
ncubica
  • 8,169
  • 9
  • 54
  • 72
2

Choose a variable name which is unlikely to be overwritten by accident and trust the programmer to not do stupid things. JavaScript is not Java, so don't pretend it was.

Also, if what you really want to do is namespacing, use a self-executing function literal:

var myLibName = (function() {
    var aPrivateVar;

    function aPrivateFunction() {}

    function accessorForPrivateVar() {
        return aPrivateVar;
    }

    // public interface:
    return {
        getPrivateVar : accessorForPrivateVar
    }
})();
Christoph
  • 164,997
  • 36
  • 182
  • 240
  • Hi Christoph, before upvoting your solution, can you please elaborate a bit what self-execute function will do here? I have tried without self-execute function call then it throws an error like `Uncaught TypeError: myLibName.getPrivateVar is not a function`. – Venkaiah Yepuri Sep 10 '18 at 09:35
1

Instead of declaring all such variables in the global scope, you could have one global object wrapping around those variables. Using Object.defineProperty() and/or Object.defineProperties() with the writable flag set to false, you can have an immutable variable.

var myObj = {};

Object.defineProperty(myObj, 'myVar', {
    value: someValue,
    writable: false
});

Or you could just use the const keyword

const MY_VAR = 10;
vlence
  • 405
  • 4
  • 8
1

Conventions and good Documentation.

You can prefix your "immutable" variable with two (or more) underscores to indicate that is something not meant to be used by others and to avoid other people's variables clashing with yours.

Maybe creating a 'namespace' like __GLOBALNAMESPACE (Ugly name, I know) and then adding your variables into it (eg __GLOBALNAMESPACE.my_var) and creating a method like this one to retrieve them:

getVariable(string name){
  return __GLOBALNAMESPACE[name]
}

Just my 2 cents.

Jason Plank
  • 2,336
  • 5
  • 31
  • 40
Pablo Fernandez
  • 103,170
  • 56
  • 192
  • 232
0

If you can use typescript, you can mark properties as readonly

Sam
  • 1
0

You might want to try out this jquery plugin. It prevents you to create global objects in javascript :)

example code

Store data

// 'val' can be a string, integer, hash table, array, object
$.secret( 'in', 'secretName', val );

// or a function
$.secret( 'in', 'secretName', function( arg1, arg2, arg3 ){
  // do something here
});

Use data; you can even use it in different files.

var lang = $.secret( 'out', 'lang' );

Call out a function

$.secret( 'call', 'secretName', [ arg1, arg2, arg3 ]);
// or
$.secret( 'call', 'secretName', arg );

Clear data

$.secret( 'clear', 'lang' );

source code is on github

Community
  • 1
  • 1
ben
  • 1,525
  • 2
  • 15
  • 15
0

The following example code makes a globally available variable immutable

Object.defineProperty(window, `env`, {
    value: Object.freeze({
        API: "https://api.mywebsite.com",
    }),
});

And it can be referenced from either window.env or just env.

Henrik Wassdahl
  • 930
  • 1
  • 10
  • 18
0

Javascript is object oriented, rather than making the variable $public static, consider making it private and then properly providing an acessor method for getting, but not setting it.

e.g.

private var myGlobal : myType;
function GetMyGlobal() : myType
{
return myGlobal;
}

There are ten different ways to solve any given problem, your way and the right way.

awiebe
  • 3,758
  • 4
  • 22
  • 33