Before we jump into the script itself, I think it may pay off to review data types and operators in Javascript. I won\'t cover them all, but the ones relevant to your code are as follows:
Data Types
Boolean
Boolean values are representative of "truth" and as such have two possible values: true
and false
. Note that within code, "true" and "false" are typically reserved keywords used to indicate these boolean values.
String
A "string" is a null
-terminated array of characters frequently designated and manipulated using string-notation (surrounding some characters in quotation marks as in \'I am a string value.\'
).
Typecasting
"Typecasting" is the process of evaluating one type of data as though it were another. Languages such as PHP and Javascript are "loosely-typed" (more formally they are languages which support "unsafe implicit type conversions") which means that many traditional operators will attempt to interpret operands as though there were a different data type in order to produce a meaningful result.
While convenient on the surface, this can lead to problems if you\'re not explicitly aware of how the language will attempt to process your expressions. The handling of booleans is a common trip-up as only (integer)0
, (pseudo-object)null
, and couple other specific values of specific types will evaluate to false
when cast as a boolean. All other values of all other datatypes are cast to boolean true
.
A good example of how typecasting can cause problems is strings and numerical math. Consider the JS expression 86 + \'12\'
- at first glance you might expect it to produce the integer value 98
, however it produces the string \'8612\'
instead. The reason is because in addition to being the mathematical addition operator, +
is also the string concatenation operator - Javascript interpreters assume you meant to interpret the integer as a string instead of the inverse.
Operators
=
The Assignment Operator
The basic assignment operator =
is used in order to attribute a named variable placed on the left of the operator with a value acquired by evaluating the expression on the right. Therefore, var a = 3 + 4;
assigns the value 7
to the variable a
.
Logical (Comparison) Operators
Comparison operators are used in order to determine how two values (the operands) relate to one another (more specifically if they are greater than, less than, or equal to each other). They produce boolean values to indicate whether or not the operands exhibit the tested relationship. In your code we are concerned with primarily the equivalency comparison, which comes in two flavors in PHP and Javascript: strict and non-strict.
==
"Equals" Operator (Typecasted)
The standard double-equals-sign comparison operator tests if it\'s two operands are "equivalent" by typecasting them to same data-type before comparing them. This means that in the comparison operation true == \'false\'
, the string value \'false\'
is cast to a boolean value - and since a string is non-zero and non-null that value is true
. Therefore the two operands are in fact "equivalent" and the operation returns true
.
===
"Strict-Equals" (or "Identity") Operator (Not Typecasted)
The triple-equals-sign comparison operator tests if the operands are equivalent as-is. More succinctly, it tests for true equivalence without typecasting. It only produces true
if the operands are in fact virtually identical. This means that the comparison operation true === \'false\'
quite simply produces false
as the two operands are in no way similar - they\'re not even the same data-type. true === \'true\'
, true === 1
, and false === null
will all produce false
for the same reason.
Code Analysis
Let\'s apply the above to your code to see what\'s going on:
<script type=\'text/javascript\'>
/* <![CDATA[ */
var CUPID = {"button":"false"};
/* ]]> */
</script>
That\'s all well and good if you want to use strings to represent your boolean values (though not recommended as it can make things much more complicated than they need to be), but keep in mind that if you try to interpret CUPID.button
as a boolean value it will evaluate to true
as it is a string. I would change this to reflect var CUPID = {"button": false};
.
window.onload = function(){
(function(){
button : CUPID.button
});
});
Quite frankly I have never seen this notation before - it looks like you\'re trying to define button
as a property of that inner closure using object notation where there should be a function body. I was surprised that my dev tools didn\'t throw a syntax error when I ran this - but could find no way to access the property or provide a function body. I suspect what you are trying to do was assign CUPID.button
\'s value to the local variable button
, which looks like this, in my book: var button = CUPID.button;
.
Another problem here is that inner closure itself - it looks like you were attempting to create an Immediately-Invoked-Function-Expression, however you omitted the parenthesis that actually execute the closure, which results in your anonymous function being defined but never actually called. A proper IIFE looks as such:
(function( parameter1, parameter2 ) {
// Function body
})( argument1, argument2 );
Note the final set of parenthesis that actually invoke the function, the same as the parenthesis on the end of any other function call. However in this instance, I see no particular reason as to why an IIFE is needed at all - I would write this code as
window.onload = function(){
var button = CUPID.button;
});
Which brings us to
if ( CUPID.button == \'true\' ) {
var btn == true;
} else if ( CUPID.button == \'false\' ) {
var btn == false;
}
The problem here is with the statements var button == true;
and var button == false;
. By using comparison operators (==
) instead of the assignment operator (=
), you are attempting to simultaneously declare a variable and compare it to another value which is impossible as you cannot compare something that does not exist. Your Javascript VM should throw a syntax error when attempting to evaluate either operation - keep an eye on your console!
Also note the caveat of comparing CUPID.button == \'false\'
- if CUPID.button
is boolean true
, this comparison will return true
(i.e. \'false\'
is true
when typecast as a boolean)! You can of course work around this issue using the strict comparison operator ===
to make the operation CUPID.button === \'false\'
(which will only evaluate to true
if and only if CUPID.button
is in fact the string \'false\'
).
There\'s also the question of the condition that CUPID.button
is neither \'true\'
nor \'false\'
- what happens then? Since the variable btn
is declared within the if/else-if
control structure, without a trailing else
to control what happens in the unlikely event that CUPID
or CUPID.button
is undefined, the variable btn
will not get declared, but your function will continue executing nonetheless! You can correct this by adding a final else
control that either declares and assigns btn
or return
s to exit the function, replacing the else-if
with an else
such that btn
will always be declared and default to false
, or defining the variable and giving it a default value before the control structure, among other ways.
Conclusions
All of that said, the following should suit your purposes fine:
// In a script evaluated before both window.onload and the localized script
/* <![CDATA[ */
var CUPID = {"button":false};
/* ]]> */
and
// In your localized script
window.onload = function(){
var button = CUPID.button;
});
Or, if you are determined to use strings in place of boolean values:
/* <![CDATA[ */
var CUPID = {"button":"false"};
/* ]]> */
and
window.onload = function(){
var button = false;
if( CUPID.button === "true" )
button = true;
});
// ...or...
window.onload = function(){
var button;
if( CUPID.button === "true" )
button = true;
else
button = false;
});
Improvements
I myself would make my script more robust to account for the conditions that CUPID
and/or CUPID.button
were never defined:
window.onload = function(){
var button = false;
// If CUPID.button is defined - use it instead of the default above!
if( typeof CUPID !== "undefined" && typeof CUPID.button !== "undefined" ) {
button = CUPID.button;
}
});
You could also make your script account for all sorts of different typed values of CUPID.button
:
window.onload = function(){
var button = false;
// If CUPID.button is defined - use it instead of the default above!
if( typeof CUPID !== "undefined" ) {
switch( typeof CUPID.button ) {
case "string":
if( CUPID.button === "true" ) {
button = true;
}
// button retains it\'s default false value for all strings besides "true"
break;
case "number":
/* This is like the conditional above - since comparisons return
* boolean values and we want button to be a boolean value, we can
* write the comparison directly into the assigned expression. */
button = CUPID.button !== 0; // All non-zero values give button true
// button retains it\'s default false value for all numbers besides 0
break;
case "boolean":
button = CUPID.button;
break;
default:
/* Handles the case where typeof CUPID.button === "undefined".
* Does nothing, since button is already given a default value
* at the top of the function body. */
break;
}
}
});
However, if your code is the only code that will be localizing values for this script this is considered sloppy - better to use booleans and only booleans unless you explicitly know that random data types will be thrown at your script by dark forces outside of your control.