Search code examples
javascriptglobal-variablesconstants

How can I create a variable that can only change its value if the new value to be assigned to it meets a predefined condition in javascript?


Image you have a global variable named window.whatever. Is it possible to prevent anyone to change its type AND its value if the new value you want to store into it doesn't meet some condition?

For example, I don't want my variable to be changed if it doesn't start with 'https://'.

In this case, window.whatever = "Hello" and window.whatever = 15 would throw an error but window.whatever = "https://example.com/" would work fine.

Maybe Object.defineProperty will fix it but I don't know how.

Object.defineProperty(window, 'whatever', {
  writable: true, //here I want to add a sort of condition
});

I tried this:

Object.defineProperty(window,'whatever',{
    set:function(x){
        if (x.startsWith('https://')) this.whatever= x}
})

but when I do window.whatever = "https://example.com" it says :Uncaught RangeError: Maximum call stack size exceeded and it's still undefined


Solution

  • UPDATE: Providing a better solution. In the previous one, __globalVar wasn't hidden and you could access it directly (read/write). This is probably not the best idea, so here's a better way:

    (function () {
      let privateValue = "Hello";
      Object.defineProperty(window, "whatever", {
        get: function () {
          console.log("in getter");
          return privateValue;
        },
        set: function (val) {
          console.log("in setter");
          if (typeof val === "string" && val.startsWith("https://")) {
            privateValue = val;
          } else {
            throw "Invalid whatever";
          }
        },
      });
    })();
    
    console.log(window.whatever);
    window.whatever = "https://stackoverflow.com";
    console.log(window.whatever);
    window.whatever = "lalala123";
    console.log(window.whatever);

    Now privateValue actually is private.


    Does something like this work for you? I think it behaves like you described.

    let __globalVar = 'Hello';
    Object.defineProperty(window, 'whatever', {
    	get() {
    		console.log('in getter');
        return __globalVar;
      },
    	set(val) {
            // put your logic here
            console.log('in setter');
            if( val.startsWith("https://") ) {
                __globalVar = val;
    	      } else {
                throw "Invalid whatever"
            }
        }
    })
    
    console.log(window.whatever);
    window.whatever = "https://google.com";
    console.log(window.whatever);
    window.whatever = "lalala123";
    console.log(window.whatever);