Sunday, October 9, 2011

Interesting JavaScript Discoveries


Every language has its own idiosyncrasies -- ways that this language behaves differently from expected.   This is my own list of discoveries that I made in the first few months of using JavaScript.
SYNTAX
It is almost amusing that JavaScript is so loose in many respects (variable declaration, data types, function parameters, etc.) but so tight in other respects (case sensitivity).  The developer must simply learn where it is "tight" and be sure to conform.
  • JavaScript is generally forgiving about including zero, one or more spaces around operators (e.g. x-1 vs x - 1 a==b vs. a == b)
  • JavaScript is very specific about case:
    • JavaScript keywords are generally lowercase: "if", "var", "document", "write".
    • JavaScript object names are mixed case: "Array", "Object", "Date"
    • JavaScript lets you name (and use) two methods or two variables that only differ by case (e.g. calcRate and CalcRate can coexist and perform different purposes)
VARIABLES
Experienced developers will probably find the JavaScript's "looseness" around variables to be its most shocking feature.  Variables are discussed in more detail elsewhere however the some points will be restated here:
  • Declaration: Variables do not have to be declared before being used.   When they are declared, they are simply defined as "var" (for variable) with no data type.
  • Data Type: A variable's data type is defined by the last value assigned to it (so called "dynamic typing").  A variable could be a number on one line, then assigned a string value and later be assigned an object reference.  JavaScript would just change its data type on-the-fly with each assignment.
  • Initialization: Variables don’t have default initialization and JavaScript does not fail if you try to use a variable that is not defined. As a string, its uninitialized value is "undefined". As a number, its uninitialized value is "NaN" a special value meaning Not a Number. Clearly, numbers and strings can be corrupted when combined with an uninitialized value.
  • Variable Access: Any variable that is not a function variable (i.e. defined within a function) will be global (i.e. accessible anywhere).
  • Beware Automatic Conversion: With some exceptions (e.g. some cases with early Netscape 4.x), JavaScript will attempt to convert variable types to make them work.  Consider the code extract:var x = ""; // emtpy string
    var y = 0; // the number zero

    if(x == y) ...


    JavaScript will attempt to synchronize their data types before the comparison takes place.   The result of "if(x==y)" would be true. Similarly, if I call the function isNaN(x) (x defined as above), x will first be translated to zero and therefore deemed as a valid numeric.

    So how do you distinguish between empty string (x) and the number zero (y)?  The typeof function can help sort out the initial data type (before JavaScript attempts to translate it).  For example "typeof x" would evaluate to "string" while "typeof y" would evaluate to "number". 
  • JavaScript-Java Data Type Compatibility: JavaScript has a looser definition of a number than Java.  For example, the following are valid JavaScript integers "+5" "2." " 8 " (return False to isNaN) but all of these will fail a string-to-integer data conversion in Java.  This would be a problem if you are submitting HTML page elements to a JSP or Servlet.  One simple solution is to have JavaScript multiply the value by one before submission so the extraneous characters (+, space, etc.) that bother Java are removed.  Including the following code in pre-submission logic will solve the problem:
if (!isNaN(document.formMain.txtNum.value)) { // valid number
  document.formMain.txtNum.value = document.formMain.txtNum.value * 1;
} else {
  // appropriate error (non-numeric in numeric field)
}
FUNCTIONS

  • Parameters: JavaScript is "forgiving" about the number of parameters that you pass a function. If you supply too few, it will assume that the later (missing) parameter values are Null. If you supply too many, the function call will still work and the extra parameters will be included (along with the defined parameters) in the function’s arguments property (an array).
  • Overloading: Function overloading is supported only in the sense that you can pass any number of parameters to a single function then you can use the arguments property to deal with the actual number of parameters passed in. You cannot, however, define the same function twice (e.g. once with one parameter and once with two parameters) and expect JavaScript to select the instance with the appropriate function signature (as Java or other more sophisticated languages do). If you define the same function twice, JavaScript will use the function instance defined later in the script and ignore the earlier definition.
  • Parameter Passing by Value/Reference: Simple data values (e.g. string, number, boolean) are passed by value into functions (so any updates to the parameter do not persist after the function is complete). By contrast, objects (e.g. a form, a custom object) are passed by reference (so updates to the parameter persists after the function is complete). When the return value is used for other purposes, the cleanest way to cause a data value to be returnable (i.e. have its value persist after the function is complete) is to make that data value part of a custom object.
  • Duplicated Name: If you accidentally give a form element name the same name as a function name, you cannot call the function (e.g. calling a button "hideList" will mean the hideList JavaScript function cannot be called).
STATEMENTSIF
  • Nothing is flagged, if you try to evaluate (a = b). b is assigned to a and, if the b is non-zero, it evaluates to true.  The same is try for while (a = b)
  • outer brackets around the full "if expression" being evaluated are mandatory, including when the whole result is negated. For example, the outer brackets are required here: if (! (a==b))
  • Navigator does not treat 1 = "1" (number 1 equal to string 1) but IE does treat them as equal. Result: make sure data types are the same before comparing to ensure Navigator compatibility.
SWITCH
  • if the break is omitted at the end of a case clause, execution continues in the next case statement (until a break or the end of the switch statement is reached).
OBJECT REFERENCES
  • From a form element, this.form is generic code which provides a handle back to the parent form.
FORM ELEMENTSSelection List

  • Selection list text and values are automatically converted to string
  • Selection lists automatically size to the widest element. You therefore always have to include some data (e.g. a prompt) in the first element, if there is any chance that the list might be empty at anytime in the process. A selection list with zero elements shrinks to a very narrow size (and looks bad).
  • Navigator does not automatically refresh the size of a selection list (but IE does). For Navigator, you must call history.go(0) to refresh the whole page and thus the selection list size.

No comments:

Post a Comment