JavaScript defined
Check whether a constant exists
1 2 3 4 56 7 8 9 1011 12 13 14 1516 17 18 19 2021 22 23 | function defined (constant_name) { // Check whether a constant exists // // version: 909.322 // discuss at: http://phpjs.org/functions/defined // + original by: Waldo Malqui Silva // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + revised by: Brett Zamir (http://brett-zamir.me) // % note 1: Because this function can (albeit only temporarily) overwrite a global variable, // % note 1: it is not thread-safe (normally not a concern for JavaScript, but would be if used // % note 1: in a threaded environment, e.g., DOM worker threads) // * example 1: defined('IMAGINARY_CONSTANT1'); // * returns 1: false var tmp = this.window[constant_name]; this.window[constant_name] = this.window[constant_name] ? 'changed'+this.window[constant_name].toString() : 'changed'; var returnval = this.window[constant_name] === tmp; if (!returnval) { // Reset this.window[constant_name] = tmp; } return returnval; } |
Examples
Running
1 | defined('IMAGINARY_CONSTANT1'); |
Should return
1 | false |
Dependencies
No dependencies, you can use this function standalone.
Open syntax issues
php.js uses JsLint to help us keep our code consistent and prevent some common bugs.
Eventually we want all code to pass or at least take into consideration most fixes suggested by JsLint, following this JsLint configuration we’ve decided on.
Authors
Thanks to the following developers, you get to have defined goodness in JavaScript.
Ok, as far as "not-null", that should be changed to "changed" (to be more clear). That is just providing some way to ensure that an undefined variable will return false (since "changed" will not equal 'undefined'). We need to do some test for whether it is defined, since it will otherwise throw an error. This is safe since the value will be reset back to its original value (in this case to undefined).
As far as the NaN issue in the function... NaN is actually is considered to be typeof number, but that was redundant, and I shouldn't have handled it as a constant anyways because I've since discovered NaN, Infinity, and undefined are all variables in JavaScript--you can change them!
The only way that adding the 'changed' keyword to the "variable" could result in the same value as the original temporary variable is if the original was a constant. For example, (non-constant) objects or arrays will have their toString() methods called, but they will get an additional string "changed" appended, so they can never match (and thus the variable will get set back to its original value).
As far as failing, I don't see any reason which could cause it to fail--do you? (if it crashed at that point, the changed variable would be meaningless anyways).
As far as a parallel process, even if the person is using a setTimeout "thread", my understanding is that the function must fully complete before yielding since JavaScript doesn't have true threads. So the variable should always get set back, as far as I can tell.
(Off the subject, but speaking of setTimeout, I just realized we could allow passing of PHP-style callbacks-as-strings into JavaScript functions by calling setTimeout with a 0 ms timeout (optionally building arguments to pass in as necessary).)
1
2
3
4
5 | var a = function(b){alert('aaa');} runCallback('a') function runCallback (cb) { var a = setTimeout(cb+"()",0) } |
Ok, now here's the simplified defined() function:
1
2
3
4
56
7
8
9
| function defined (constant) { var tmp = window[constant]; window[constant] = window[constant] ? 'changed'+window[constant].toString() : 'changed'; var returnval = window[constant] === tmp; if (!returnval) { // Reset window[constant] = tmp; } return returnval; } |
@ Brett Zamir: If I'm not mistaken you are reassigning the variable a value to make sure it really is a constant.
If it's not set, you set it to not-null? That part I don't get.
Then, if it's a number AND it's not a number (?!) and the types of the original & newly set var do not match you reset it to it's original value. But if they do match you leave the 'changed' keyword there? I don't understand that.
One concern that comes to surface is that you are changing a user variable (if they accidentally specify a variable instead of a const).
If the function fails or there is a parallel process, a the changed value will be returned.
Could you explain a bit more about this approach? I'm just not getting it I guess.
Whoops... forgot to reassign the variable I temporarily changed:
1 2 3 4 56 7 8 9 1011 12 13 14 1516 17 | function defined (constant) { var returnval; var tmp = window[constant]; window[constant] = window[constant] ? 'changed'+window[constant].toString() : 'not-null'; if (typeof window[constant] === 'number' && isNaN(window[constant])) { // NaN returnval = typeof tmp === typeof window[constant]; if (!returnval) { window[constant] = tmp; } return returnval; } returnval = window[constant] === tmp; if (!returnval) { window[constant] = tmp; } return returnval; } |
Here's an implementation which works with the 'const' keyword. Tested with NaN, booleans, numbers, strings, arrays, objects, regular expression literals.
1 2 3 4 56 7 8 9 1011 12 13 | const a = 5; var b = 5; alert(defined('a')); // true alert(defined('b')); // false function defined (constant) { var tmp = window[constant]; window[constant] = window[constant] ? 'changed'+window[constant].toString() : 'not-null'; if (typeof window[constant] === 'number' && isNaN(window[constant])) { // NaN return typeof tmp === typeof window[constant]; } return window[constant] === tmp; } |


Brett Zamir
26 Jan '09