My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.

Monday, October 29, 2007

[COW] JavaScript define PHP like function

This time my personal COW is a quite totally cross browser function to define a JavaScript constant.

With FireFox or Safari a const variable should be nested or global but the most important thing, it cannot be assigned two times

const scriptCantChangeMe = "some text";
scriptCantChangeMe = "something else";
alert(scriptCantChangeMe); // some text


A constant should be every kind of JavaScript variable and if this feature will be available on future versions of Internet Explorer and Opera, a lot of security problems should be solved (think for example about JSON, Array, Object and every other constructor, method or callback).

Unlikely We can't use this feature with Opera browser and, quite more important, Internet Explorer doesn't support JavaScript constants.

The only way to create a global scope constant variable with Internet Explorer is using another language: VBScript

This IE dedicated language supports PHP like defined constants: scalar values like integer, float, string or boolean.


JavaScript define function


This function works like PHP define one, except for last argument, case-sensitive, and it is compatible with Internet Explorer (maybe every version), FireFox 2 or greater, Safari 2 or greater and finally Opera 9 o greater too.

define("MY_NOT_MUTABLE_VALUE", 123);
alert(MY_NOT_MUTABLE_VALUE); // 123
MY_NOT_MUTABLE_VALUE = 456; // error with Internet Explorer
alert(MY_NOT_MUTABLE_VALUE); // 123 with both FireFox and Safari


The most important thing is that You can't change arbitrary a defined constant and it should be useful in many different cases.

Only Opera 9 has a wrong const implementation because it's just a var alias and not a real constant creation.

Since Opera hasn't a watch Object prototype and since a prototype should be always defined everywhere, this last browser is compatible but it allows value mutation so please remember this when (and if) You choose to use my define proposal.

Finally, please remembre that a constant should respect some rules:

  • its name must be UPPERCASE (MY_CONST instead of MyConst or my_const)

  • its name should have a dedicated prefix/suffix to don't be intrusive (MY_LIB_NAME_INITVALUE instead of INITVALUE)



Remark: to ensure cross browser compatibility every value is parsed by function, checking for its toString native or assigned returned value.
This means that define("MY_BOOL", "true") creates a constant called MY_BOOL that will be exactly a boolean true value and the same thing happens if You use "false" that will create a boolean false constant.
This is true for numbers too:

define("MY_STRING", "123") === define("MY_NUMBER", 123); // true
define("MY_STRING", "true") === define("MY_BOOLEAN", true); // true
define("MY_STRING", "-123.456") === define("MY_NUMBER", -123.456); // true


That's all :-)

5 comments:

Anonymous said...

Woah!! This is great!

How on earth nobody has still left a comment?!?!

I see many uses for this including the new version of my project Primera.

Bravo! :)

Sebastian.
www.sebastian.it

Alessio said...

very clear post, enlightening!

thank you

Gareth Heyes said...

I know I'm late but I needed this! Great work thanks

DBJDBJ said...

Improved. added "chaining" , and used IE JScript condition comments.

usage :

define("A",1)("B", 2)("C", 3) ;

next: redefine() and undefine()

--DBJ


define = (function(){
function as_const(name, value){
return "const " + name + "=" + (
/^(null|true|false|(\+|\-)?\d+(\.\d+)?)$/.test(value = String(value)) ? value : '"' + replace_(value) + '"'
)
};
var define_, replace_;
replace_ = function(value){
var replace = {"\x08":"b","\x0A":"\\n","\x0B":"v","\x0C":"f","\x0D":"\\r",'"':'"',"\\":"\\"};
return value.replace(/\x08|[\x0A-\x0D]|"|\\/g, function(value){return "\\"+replace[value]})
};
define_ = function(name, value){
var script = document.createElement("script");
script.type = "text/javascript";
script.appendChild(document.createTextNode(as_const(name, value)));
document.documentElement.appendChild(script);
document.documentElement.removeChild(script);
return define_ ;
}
/*@cc_on
// only IE version, uses VBScript
replace_ = function(value){
var replace = {"\x0A":"\\n", "\x0D":"\\r"};
return value.replace(/"/g, '""').replace(/\n|\r/g, function(value){return replace[value]})
};
define_ = this.execScript ?
function(name, value){
execScript(as_const(name, value), "VBScript");
return define_ ;
}:
function(name, value){
eval(as_const(name, value).substring(6));
return define_ ;
}
@*/
return define_;
})();

Andrea Giammarchi said...

er, DBJ ... the title is:
JavaScript define PHP like function
thanks for ths snippet but that's not PHP like.

Plus a redefine function will make everything a non-sense and constants consistency will disappear.

A constant IS a constant, thanks lord we cannot redefine them, or if we can, it's just a BUG