Netscape Network ad
____________________

JavaScript 1.2's evolution as explained by its creator

Brendan Eich provides an enlightening description of 1.2's data types, as the language continues to search for its own identity and a universal standard

By Lisa Rein

NetscapeWorld
has become
[Netscape Enterprise Developer Table of Contents]

May 1997
[May 1997 Table of Contents]Table of Contents
[Archives]Topical Index
[Search]Search

Summary
Is JavaScript a standard? Can something be a standard without a specification? A scripting standard that Netscape promises to follow is not far off, only the specification won't be called "JavaScript." How does the name "EcmaScript" grab you?

We begin with a discussion about the unusual path that Netscape has chosen to standardize the JavaScript language. Since there is no single specification detailing JavaScript's syntax and usage, we provide a collection of every JavaScript reference document on Netscape's site. We move on to discuss some of the new ways that JavaScript handles data types, fleshing everything out with comments and examples from JavaScript creator Brendan Eich. Eich explains what went wrong with the LAYER offset() attribute, why the Equality Operator model had to be modified, and tells us what developments we can expect in JavaScript's future.

Also presented is a coding scenario solution for providing backwards-compatibility with non-1.2-JavaScript-enabled browsers, featuring a handy checklist of the many varying factors to consider when coding JavaScript for backwards-compatibility in general. (3,900 words)

Today, if you want a complete explanation of JavaScript's syntax, rules, and proper usage, you need to figure them out for yourself by comparing the 52 JavaScript reference documents littered throughout Netscape Communication's Web site. Don't worry, we've compiled a comprehensive list of them for your convenience.

Of these documents, many are obsolete (albeit nicely-indexed), all are poorly cross-referenced, and even occasionally contradictory. (The only consistency these documents share are their disclaimers.)

The last few months, the naming and usage of JavaScript's events and methods have been repeatedly altered, replaced, or "renamed for consistency" with the coming of each new Communicator Preview Release. Different preview versions and platform-specifics only add to the confusion. At present, although complete backwards-compatibility is touted, it is not explained, and in no way guaranteed. Perhaps JavaScript is the first example of a widely implemented scripting language that doesn't guarantee backwards-compatibility, nor does it offer any guarantees about its current functionality either.

For example, in Netscape's document titled "Codestock on JavaScript 1.2 Enhancements", in the "Q & A Session" on "Positioning and Layering HTML documents", one of the questions reads:

"The offset() method for layers is being renamed moveBy() for consistency with the naming of window methods. Will offset() still be supported for backwards compatibility?"

and Netscape's answer is:

"It will probably still work in the preview releases. It may be removed from the final release."

Another example can be found in the Release Notes for the "early" release of the Windows Communicator PR4. (Yes, the "early" release of a "preview.") In the "developer information" section, it reads:

"Every layer in JavaScript now has a DOCUMENT property that scopes all the reflected HTML objects inside the layer. Similarly, JavaScript code exists inside a <LAYER> tag will be scoped to the containing layer rather than the window. THIS CHANGE MAY BE INCOMPATIBLE WITH SCRIPTS DESIGNED TO WORK WITH COMMUNICATOR PR2."

Why all the changes?
These constant changes can be explained with one word: BETA.

"That's just beta flux," said JavaScript creator Brendan Eich. "You have to allow for that if you start to develop for a beta. It really was a mistake that the folks working on window.moveBy and the folks working on layer.offset didn't get together ahead of time. We could leave behind a layer.offset synonym to make old beta code work, but why preserve a deprecated name and make our code more complicated if we can help it?"

ECMA who?
A brief investigation of the ECMA Web site proved enlightening.

ECMA has recently added five new members to its "General Assembly":

Also, a new Technical Committee was formed: ECMA TC39 - Scripting Languages. It's stated "scope" is "To standardize the syntax and semantics of a general purpose, cross-platform, vendor-neutral scripting language", and the Committee is chaired by Sun's Gary Robinson.

The main difference between Ordinary Members and Associate Members seems to be that Associate Members don't get a vote in the general assembly, only pay half of an Ordinary Member's dues, but there may be more to it, so see ECMA's bylaws for yourself.

Here's what ECMA's hierarchical structure looks like:

[ECMA organizational chart]

Dealing with data types in JavaScript 1.2
There are three "primitive" types of data JavaScript programs can manipulate: numeric, string, and Boolean literals. For a numeric data type, its value is represented simply with a number. For a "string" data type, its value is represented by text: a string of letters, digits, or punctuation characters, and are placed between pairs of single or double matching quotes. (Indented comments are quotes from Brendan Eich.)

"You might want to mention that newlines and quotes can appear in a string if preceded by \, also the \076 and \x3e octal and hex escape sequences."

Boolean values are often generated by comparison operators in order to determine the correct path of action in a JavaScript's control structure. An if/else statement, for example, where the Boolean result is "true" will instruct JavaScript to perform one action while a "false" result will trigger a different action.

Boolean data types can have only two possible values: true and false ("on and off", "yes and no", or even "1 and 0").

"The sense of true and false can be thought of as "yes" and "no" respectively, but some new JS authors might take the above to mean that "0" is equivalent to false. It's true that 0 converts to false, as does the empty string "" or '', but "no" converts to true because it's a non-empty string.

"I've found you can't be too careful in explaining the conversion rules, from experience with developers and the ECMA standardization process."

There are also objects, and arrays: data types that are more complex and are compared by reference. Two object or array variables are only equal if they refer to the same object, array or function. So two separate arrays will never be equal, by definition, even if they contain the same elements.

"Null" is a special value for an object variable that indicates "no value", meaning it doesn't contain a valid object, array, number, string, Boolean value, or function.

Datatype considerations when declaring variables
Using a variable that doesn't exist will cause problems.

"Actually, you'll get an error if you use (a variable) without first setting it (thus creating a global or top-level variable), or declaring it with var."
A variable will return an "Undefined" value if you've used an object property that doesn't exist, or a variable that was declared, but never had a value assigned to it.

So if we write:

my.prop == null

it will return true if either my.prop doesn't exist or if it exists but contains the value null.

However, if you use typeof on null, it returns "undefined".

"That's because JS has until 1.2 considered "undefined" to be equal to "null". In 1.2 we're tightening things up so they aren't equal. The simplest way to test whether a property or variable that should refer to an object is not undefined and not null, in all versions of JS, is:"

    if (obj.prop) {
        // obj.prop refers to a valid object
    }

If you attempt to append a number to a string, JavaScript will automatically convert the number to its corresponding string so that it can be appended.

"1" + 0 = "10"

"It's probably helpful to point out that this situation arises only with +, which means string concatenation if either operand is a string or object that converts to a string.

You can convert a string to a number many ways (roughly in order of efficiency and clarity):"

    Number("1") + 2   == 3
    ("1" - 0) + 2     == 3
    parseInt("1") + 2 == 3
    eval("1") + 2     == 3

With comparison operators, the definition of "equal" depends on the data type (numbers, strings, or Boolean). Two numbers must have exactly the same numeric value. Two strings are equal only if they each contain exactly the same characters.

Usually, if two values have different data types, by definition, they are not equal.

"This is true always (not usually) only in JS1.2. In earlier versions, and if you don't specify a version (SCRIPT LANGUAGE=JavaScript), then conversions are applied as follows:"

    if (both operands are objects)
        compare object references;
    else if (either operand is null)
        convert the other to object and compare references;
    else if (both operands convert to string)
        compare string conversions by value;
    else
        convert to number and compare;

If the expression "1" == 1 evaluates to true, and true == 1 and false == 0, are both expressions not true because they happened to have string values that converted easily to numeric values?

"Not so -- neither true, nor false, nor 0 nor 1 are strings, nor do they need to be converted to string in order for JS (old or unspecified versions) to consider them to be equivalent: if you plug and chug in the pseudo-code above, you'll find they all convert directly to number (false to 0 and true to 1) and compare accordingly, as numbers."

Navigator 2.0 will also incorrectly return true for Null == 0, but that's fixed in Navigator 3.0.

If you do accidentally compare a string to a number and the string cannot be converted to a number, then Navigator 2.0 and 3.0 will produce an error message, while IE 3 will simply return "false". So you need to be careful of the data types when working with your variables, or an incorrect Boolean value will trigger the wrong action.

"Another bug, fixed in 4.0: undefined and strings containing non-numeric literals convert to NaN (Not a Number), a special IEEE754 floating point pattern (set of patterns, really) that does not equal any other number or itself, and is neither less than nor greater than any other number."
The equality operators (== and !=) work differently if the SCRIPT tag uses LANGUAGE=JavaScript1.2. If either LANGUAGE=JavaScript1.1 or LANGUAGE=JavaScript are used, the equality operators will maintain their previous behavior, which is:

If LANGUAGE=JavaScript1.2 is used, the equality operators (==, !=) use a different criteria when comparing mismatched data types in order to return a Boolean value.

For this reason, you must convert operands manually when writing for all JavaScript versions of Navigator:

To convert x to a string, use " " + x. For example,

(("" + 3)=="3")

To convert x to a number, use (x - 0). For example,

(("3"-0)==3)

When writing for JavaScript 1.2 only:

To convert x to a string, in addition to " " + x, you can use String(x) when you declare the variable. For example,

var x = 3 String(x) = "3"

"There's no need to introduce a variable here, and I'm afraid new users will fear they have to do so, and proliferate useless variables superstitiously. Better to minimize:"

String(3) == "3"

To convert x to a number, in addition to (x - 0), you can use Number(x). For example,

var x = "3" Number(x) = 3

Examples

ExampleBoolean ValueBecause/PrecedenceSo
<SCRIPT> document.write("3" == 3); </SCRIPT> TRUE**old model wants to convert one of them and numbers take precedence over strings, unless +("3" == 3)
or
((3-0) == 3)
or
3=3
<SCRIPT> document.write(("3"-0) == 3);
</SCRIPT>
TRUEparentheses forces "3" to convert to number to perform subtraction operator first (which requires number values)((3-0)-0)==3
or
((3-0)==3)
or
(3==3)
<SCRIPT LANGUAGE="JavaScript"> document.write("3" == 3);
</SCRIPT>
TRUE**wants to convert one of them and numbers take precedence over strings, unless +("3" == 3)
or
((3-0) == 3)
or
3=3
<SCRIPT LANGUAGE="JavaScript1.1"> document.write("3" == 3);
</SCRIPT>
TRUE**wants to convert one of them and numbers take precedence over strings, unless +("3" == 3)
or
(3-0) == 3
or
3=3
<SCRIPT LANGUAGE="JavaScript1.2"> document.write("3" == 3); </SCRIPT> FALSEInherently false because different data types.
<SCRIPT LANGUAGE="JavaScript1.2"> document.write(("3"-0) == 3); </SCRIPT> TRUEparentheses cause "3" to be converted to number due to requirement of subtraction operator ((3-0)-0)==3
or
((3-0)==3)
or
(3==3)
<SCRIPT LANGUAGE="JavaScript1.2"> document.write(String(3) == "3"); </SCRIPT> TRUE1) Both are strings
and
2) they contain exactly the same characters
("3"=="3")
or
"3"=="3"

**NOTE regarding row of table:

The following rule will be revised in the forthcoming ECMA standard for JavaScript (EcmaScript):

<SCRIPT>                     
document.write("3" == 3);     numbers take precedence
</SCRIPT>                     over strings, unless +

"The old model wants to convert one of them, and numbers take precedence over strings, unless "+" is used, but that will no longer be the case. The new standard will give strings precedence.

"What's the difference, you ask? Converting to number rather than string ("numbers take precedence") means both "3" and "3.0" (and "3.00", etc.) equal 3, but "3.0" does not equal "3" -- the relations "3" == 3 and 3 == "3.0" do not imply "3" == "3.0".

"This means == is not transitive. Transitivity is considered desirable for equality operators. Equality operators, according to purists, should be equivalence relations (transitive, reflexive and symmetric).

"So for the ECMA standard, strings will take precedence and there is exactly one string conversion of a given number: 3 converts to "3", not to "3.0" or "3.00". So the result is that "3" == 3 but "3.0" != 3, in the ECMA standard."

Q & A with Brendan Eich. JavaScript's creator
What's going on with the JavaScript "standard"?
We will be standardizing our extensions via ECMA. The ECMA TC39.1 group is finishing up the standard for a June ECMA general assembly vote, I believe.

What's your stand on the <LAYER> tag and the way Netscape has moved forward with its implementation apparently in spite of its apparent parallel implementation of the CSS1 standard?

First, Netscape co-authored the CSS draft standard for positioning containers, or whatever they're called.

Second, our customers want tags, which are more concise, expressive, and compatible with HTML "programming" than CSS.

Why do we need <LAYER> when there can be a cross-browser solution using HTML and CSS?

People who want to code for browsers not supporting <LAYER> may find the things they can do limited by CSS. If they want to do dynamic layers, they'll have to use another vendor's proprietary object model scripting anyw

We expect to participate through the W3C in HTML object model standardization, but that has not really started yet.

Why you would need to "signed scripts" for since JavaScript can't make system calls anyway?

But it can, via Java. A signed-script whose principals you trust to write a file can do so using LiveConnect.

And even without Java, there are many operations that we've forbidden unsigned JS from doing (sending mail, looking at another window's history if the window loads a document from a different server, etc.).

Am I to understand that if you wanted to code backward compatibility you'd have to not only use the language attribute for 1.0, 1.1 and 1.2, but hide all of the contents in comment tags?

Sure. The comment-hack is needed for browsers that don't grok SCRIPT at all.

I suspect no one would bother with LANGUAGE=JavaScript1.2 in addition to a least-common-denominator script, just for the sake of using both sets of operators or because the new equality operators are simpler to define.

Why then, use LANGUAGE=JavaScript1.n" at all?

Well, for precisely the same reason that we added LANGUAGE=JavaScript1.1 in 3.0 to help users hide scripts that updated image source URLs from Navigator 2.0 users, the real payoff for the extra work of a LANGUAGE=JavaScript1.2 script will only seem worthwhile once you start using the new killer features (regular expressions, layers, etc.) to add real pizzazz to your page.

Is it possible to define an object and call to it one way with JavaScript 1.2, call to it another way with JavaScript 1.1, and theoretically call it yet a third way with JavaScript 1.0, without having the various events getting in each other's way. Does Communicator just "know" which, if any, functions/events won't work together so it picks one (presumably 1.2...)

No, it reads them all in order. So if you want your 1.2 functions to trump any older versions, put the 1.2 script tag last.

Why go to ECMA?

Many reasons, among them ECMA's reputation for fairness and speed of standards process.

When do you estimate JavaScript becoming any kind of standard?

There is an ECMA General Assembly meeting in June at which I believe a vote will be held on the "EcmaScript" specification. We believe it should be approved and then become an ECMA standard, with a freely available and rigorous language specification.

Any why do you keep changing the names of events and things, such as the LAYER method offset() that was renamed to moveBy(), when that could jeopardize backwards-compatibility?

What about window.innerHeight and window.innerWidth then? From a developer's standpoint, doesn't that just complicate things?

Developers were finding their old code that set (but never declared with var) "width" and "height" variables would break -- would set the window's inner width and height instead of setting their variables -- in 4.0PR2 or whichever it was that we shipped window.width and window.height as properties.

Again, we have to be able to fix beta bugs including naming bugs, or what's the point of beta? A beta feature is not as strong a promise of compatibility as a final .0 release feature, although we don't take name changes lightly even in betas. For window.width and window.height , we had no choice -- those names are too common in code developed for 3.0 and 2.0.

We could have tried to use LANGUAGE=JavaScript1.2 as a necessary condition for defining the window.width and window.height properties, but that leads to complicated tests in our code, and likely confusion for users. We'd rather extend existing the window object with names that are less likely to collide with names that developers have already chosen for their global variables.

And where possible, we let the developer's name "win" and hide the new name we're trying to predefine. We do this by "lazy" or "late" binding -- only when the developer's script refers to "screen" but does not assign to it for instance, do we make the new screen object available. We didn't use this technique for innerWidth and innerHeight, or a few other pairs of new properties, however, to avoid undue complications in our source code. We haven't found scripts that use those names already, but there are many that use "width" and "screen" for their own variable and function names.

Note that we did keep "width=" and "height=" window.open options, of course -- no way to remove those without breaking the world, even though we do provide the "innerWidth=" and "innerHeight=" option synonyms. As a matter of style, new LANGUAGE=JavaScript1.2 scripts should probably use "innerWidth=" and "innerHeight=" to be clear -- the old names are of course required for LANGUAGE=JavaScript, and what they mean is well-defined, but their names do not connote "inner," at least to me.

We want to assure people that we won't be adding names carelessly in the future, and that we hope to have other ways of separating our predefined names from names defined by developers.

Skillful scripting for graceful degradation
JavaScript 1.0, 1.1, and 1.2 have separate specifications. Some documentation compares functionality between versions 1.0 and 1.1, and some even throw caution to the wind and state clearly what is probably going to be changed, but all are effectively disclaimed as "preliminary" documents and subject to change without notice.

At first glance, JavaScript's backwards-compatibility strategy seems very straight forward, almost foolproof, but the details get very confusing very fast.

There are several approaches to providing backwards-compatibility to the visitors of your site. One way is to code two completely different pages and use a script to figure out who's got what browser and then serve them that page accordingly.

Another option is to code for multiple versions for JavaScript and let the browsers decide.

Here's a checklist to use when using several SCRIPT LANGUAGE= tags in a single document for preserving backwards-compatibility.

  1. Use the SCRIPT LANGUAGE attribute at all times.
    JavaScript written for Navigator 4.0 may work in Navigator 4.0 only, so to ensure that users of earlier versions of Navigator avoid problems when viewing pages that use JavaScript 1.2, use the LANGUAGE attribute in the SCRIPT tag to indicate which version of JavaScript you're using.

    Since statements within a SCRIPT tag are ignored if the browser does not have the level of JavaScript support specified in the LANGUAGE attribute, the browser will keep going until it sees something it can interpret.

    By using the LANGUAGE attribute, you can write general JavaScript that Navigator version 2.0 and higher recognize, while still including additional or refined behavior for newer versions of Navigator.

    If you use SCRIPT LANGUAGE="JavaScript1.2", you need to be aware that JavaScript 1.2 will only work in Navigator, 1.1 will work in Netscape 3.0 and IE 4.0, and 1.0 will work in Navigator 2.0 and IE 3.0.

  2. Comment-out all your SCRIPT code
    You still have to enclose the textual code of your SCRIPT with comment tags (<!-- and //-->) or the non-JavaScript-aware browsers will write your events and function calls as text on the screen.

    Older browsers that don't recognize the SCRIPT tag will pass right over it, and render its contents as text Conversely, when JavaScript-aware browsers scan the SCRIPT tag's contents, they recognize the comment tag as the first line of a JavaScript program, so they execute the instructions. In fact, JavaScript has its own comment tag:

    document.write(3-"0");
 // this is how you'd leave a comment
 // you can leave as many as you like without them being read

So if your coding for backwards-compatibility, you better comment out the contents of all your SCRIPT LANGUAGE="JavaScriptX.X" tags, even though Communicator doesn't need this precaution, all the people you want the page to degrade to will.

Like this:

<SCRIPT LANGUAGE="JavaScript">
 <!--
   hacks_img=null;
   function whack_image(img)   { }
 //here is where yo would put your comments
 //-->
</SCRIPT>

<SCRIPT LANGUAGE="JavaScript1.1">
 <!--
  function whack_image_name(img, i) {
    return img.src.substring(0, img.src.length - 5) + i +
           img.src.substring(img.src.length - 4);
  }
  function whack_image(img)   { img.src = whack_image_name(img, "2"); }
 //pretty darned exciting, isn't it!
 //-->
</SCRIPT>

  1. Terminate all statements with a semicolon
    Although semicolons are optional if your statements already exist on separate lines, properly terminating your statements provides added protection if your script file's formatting is somehow altered by the forces of nature.

    Terminating your statements from the get-go will also with the process of elimination when you're troubleshooting your code later.

  2. Load any images or applets completely in the HEAD
    You will usually want to have your applet or images fully-loaded before your JavaScripts call to them. One way to give them a head start is by pre-loading them in the HEAD of your document, where they will wait in your user's cache patiently until invoked by a user-event or conditional statement.

    You can also use hidden frames or pixel-sized images to do tricks for you, but how those kinds of tricks behave "out there" on the browsers of the world will be entirely out of your control.

If you have a working example of JavaScript Functionality that gracefully degrades from JavaScript 1.2 to 1.1 to 1.0 to a text file, let us know. []

Resources

JavaScript 1.0 references

JavaScript 1.1 JavaScript 1.2 Communicator Documentation
  • Communicator Preview Documentation http://developer.netscape.com/library/documentation/communicator/
  • Dynamic HTML Resources A collection of sites featuring resources for and examples of Dynamic HTML, a set of technologies incorporated into Netscape Communicator for the creation of rich, interactive Web pages. http://developer.netscape.com/library/documentation/ htmlguid/dynamic_resources.html
  • Customizing LDAP Settings for Communicator http://developer.netscape.com/library/documentation/ communicator/software/custom.htm
  • Table Improvements in Netscape Communicator http://developer.netscape.com/library/documentation/ communicator/software/tables.htm
  • Netscape Communicator Reviewers Guide http://home.netscape.com/comprod/products/ communicator/guide_intro.html
  • JAR Installation Manager Developer's Guide How to package plug-ins, fonts, and/or Java classes so that Communicator can automatically and securely install or update them on a user's machine when needed. This manual replaced the AutoInstall Developer's Guide (and probably the Automatic Software Download (ASD) Developer's Guide too). http://developer.netscape.com/library/documentation/ communicator/software/jarman/index.htm
  • Composer Plug-in Guide The Composer Plug-in Guide tells you how to develop plug-ins that extend the HTML-editing functionality of the Netscape Composer and Message Composition windows on any operating system that supports Java. http://developer.netscape.com/library/documentation/ communicator/software/composer/plugin/index.htm
  • Plug-in Guide The Plug-in Guide tells you how to develop plug-ins that extend Netscape Communicator with a wide range of interactive and multimedia capabilities. Plug-ins are native-code extensions that behave as though they are part of the Communicator interface. http://developer.netscape.com/library/documentation/ communicator/software/plugin/index.htm
  • Netscape Navigator 4.0 -- Java in PR 3 http://developer.netscape.com/library/documentation/ communicator/software/javapr3.htm
  • Netscape DevEdge Communicator newsgroup to discuss with your peers Communicator's features and development issues about this preview release. Netscape engineers monitor these newsgroups, although may not necessarily respond to any individual inquiry. http://developer.netscape.com/members/doc/community/doc/newsgroups/ newsgrp.html#communicator
  • Netscape's Bug Reporting Form http://developer.netscape.com/support/bugs/bugform.html
LiveWire and LiveConnect
  • Visual JavaScript Developer's Guide http://developer.netscape.com/library/documentation/ communicator/software/visualjs/vjs.html
  • LiveWire Developers Guide The LiveWire Developer's Guide explains how developers can use JavaScript, Netscape's scripting language, to help them create dynamic HTML pages and server-based applications. http://developer.netscape.com/library/documentation/livewire/index.html
  • LiveConnect http://home.netscape.com/eng/mozilla/3.0/handbook/javascript/livecon.htm
  • LiveConnect/Plug-in Developers' Guide How to write a plug-in. http://home.netscape.com/eng/mozilla/3.0/handbook/plugins/index.html
  • LiveConnecting Plug-ins with Java How to call plug-ins from Java and Java from plug-ins. http://home.netscape.com/eng/mozilla/3.0/handbook/plugins/pjava.htm
  • The Java Runtime Interface The standardized interface to communicate between the Java runtime and plug-ins within the LiveConnect environment. http://home.netscape.com/eng/jri/
  • LiveConnect Communication A section of the chapter "What's New in Navigator 3.0?" in the JavaScript Guide -- how to enable LiveConnect in Navigator 3.0. http://home.netscape.com/eng/mozilla/3.0/handbook/javascript/index.html
  • Using LiveConnect A high-level overview of the features of Live Connect. http://home.netscape.com/comprod/products/navigator/version_3.0/ building_blocks/liveconnect/how.html

About the author
Reach Lisa Rein at lisa.rein@netscapeworld.com. HYIP Monitor