Jscriptdeviationsfromes 3
Jscriptdeviationsfromes 3
Sep 24, 2007 Pratap Lakshman Microsoft Corporation This draft provides a description of JScripts deviations and extensions to ECMAScript 3rd Edition Specification. This is work-in-progress, and there are still a few sections to document or correct.
1 2
Introduction ............................................................................................................. 4 Deviations from ES3 ............................................................................................... 4 2.1 White Space: 7.2 ............................................................................................ 4 2.2 Future Reserved Words: 7.5.3 ........................................................................ 4 2.3 String Literals: 7.8.4....................................................................................... 6 2.4 Arguments Object: 10.1.8 .............................................................................. 6 2.5 Global Object: 10.2.1 ..................................................................................... 8 2.6 Array Initialiser: 11.1.4 ................................................................................ 10 2.7 Function Expressions: 11.2.5........................................................................ 10 2.8 The Abstract Relational Comparison Algorithm: 11.8.5 ............................... 12 2.9 Function Declarations used as Statements within function bodies: 12 ........... 12 2.10 Enumerating shadowed [[DontEnum]] properties: 15.2.4 ............................. 17 2.11 The try statement: 12.14 ............................................................................... 18 2.12 Array.prototype.join: 15.4.4.5 ...................................................................... 19 2.13 Array.prototype.unshift: 15.4.4.13................................................................ 20 2.14 Function length properties: 15.2.3, 15.5.3.2, 15.5.4.7, 15.5.4.8, 15.5.4.13 21 2.15 String.prototype.split: 15.4.4.14 ................................................................... 23 2.16 Number.prototype.toPrecision: 15.7.4.7 ....................................................... 24 2.17 Date.prototype.valueOf: 15.9.5.8.................................................................. 24 2.18 Disjunction: 15.10.2.3 .................................................................................. 25 2.19 Term: 15.10.2.5............................................................................................ 26 2.20 Atom: 15.10.2.8 ........................................................................................... 27 2.21 new RegExp(pattern, flags): 15.10.4.1.......................................................... 28 2.22 Date.prototype.getYear: B.2.4 ...................................................................... 30 2.23 Date.prototype.setYear: B.2.5 ...................................................................... 30 3 Implementation dependent, or underspecified, in ES3 ............................................ 31 3.1 Identifiers: 7.6 .............................................................................................. 31 3.2 The Number Type: 8.5 ................................................................................. 31 3.3 ToString Applied to the Number Type: 9.8.1................................................ 31 3.4 Function Calls: 11.2.3 .................................................................................. 32 3.5 The typeof operator: 11.4.3 .......................................................................... 32 ________________________________________________________________________ Draft Page 1 of 87
3.6 The for-in statement: 12.6.4 ......................................................................... 33 3.7 Joined Objects: 13.1.2 .................................................................................. 34 3.8 Creating Function Objects: 13.2 ................................................................... 35 3.9 eval(x): 15.1.2.1 ........................................................................................... 35 3.10 parseInt(string, radix): 15.1.2.2 .................................................................... 36 3.11 Function.prototype.toString: 15.3.4.2 ........................................................... 37 3.12 Object constructor and host objects: 15.2.2.1................................................ 39 3.13 valueOf and host objects: 15.2.4.4 ................................................................ 39 3.14 Array.prototype.toLocaleString: 15.4.4.3 ..................................................... 40 3.15 Array.prototype functions: 15.4.4.4 to 15.4.4.13 ......................................... 41 3.16 Array.prototype.sort and compare functions: 15.4.4.11................................. 41 3.17 String.prototype.localeCompare: 15.5.4.9..................................................... 41 3.18 String.prototype.replace: 15.5.4.11 ............................................................... 41 3.19 Number( [value] ): 15.7.1.1 .......................................................................... 41 3.20 Number.prototype.toString: 15.7.4.2 ............................................................ 42 3.21 Number.prototype.toLocaleString: 15.7.4.3 .................................................. 43 3.22 Number.prototype.toFixed: 15.7.4.5 ............................................................. 44 3.23 Number.prototype.toExponential: 15.7.4.6 ................................................... 46 3.24 Number.prototype.toPrecision: 15.7.4.7 ....................................................... 49 3.25 Date.parse (string): 15.9.4.2 ......................................................................... 50 3.26 Date.UTC: 15.9.4.3 ...................................................................................... 58 3.27 Date.prototype.toString: 15.9.5.2.................................................................. 58 3.28 Date.prototype.toDateString: 15.9.5.3 .......................................................... 59 3.29 Date.prototype.toTimeString: 15.9.5.4 ......................................................... 59 3.30 Date.prototype.toLocaleString: 15.9.5.5 ....................................................... 60 3.31 Date.prototype.toLocaleDateString: 15.9.5.6 ................................................ 60 3.32 Date.prototype.toLocaleTimeString: 15.9.5.7 ............................................... 60 3.33 Date.prototype.toUTCString: 15.9.5.42 ........................................................ 61 3.34 new RegExp(pattern, flags): 15.10.4.1.......................................................... 61 3.35 RegExp.prototype.toString: 15.10.6.4 .......................................................... 61 3.36 Error.prototype.message: 15.11.4.3 .............................................................. 62 3.37 Error.prototype.toString: 15.11.4.4 ............................................................... 63 3.38 NativeError.prototype.message: 15.11.7.10 .................................................. 64 3.39 Errors: 16 ..................................................................................................... 65 4 JScript Extensions ................................................................................................. 65 4.1 debugger statement ........................................................................................ 65 4.2 conditional compilation .................................................................................. 65 4.3 dynamic scoping across script engines ........................................................... 67 4.4 Function Declaration ...................................................................................... 69 4.5 function caller identification ....................................................................... 70 4.6 lastIndex property on the RegExp Captures Array .......................................... 71 4.7 RegExp.index ................................................................................................ 72 4.8 RegExp.input and RegExp.$_ ........................................................................ 72 4.9 RegExp.lastIndex ........................................................................................... 73 4.10 RegExp.lastMatch and RegExp.$& ................................................................ 74 4.11 RegExp.lastParen and RegExp.$+ .................................................................. 74 ________________________________________________________________________ Draft Page 2 of 87
4.12 RegExp.leftContext and RegExp.$` ................................................................ 75 4.13 RegExp.rightContext and RegExp.$' .............................................................. 76 4.14 RegExp.$1 RegExp.$n ................................................................................ 76 4.15 RegExp.compile(pattern, flags) ...................................................................... 77 4.16 Properties on the Error Object ........................................................................ 78 4.17 The Error constructor ..................................................................................... 79 4.18 Script engine identification functions ............................................................. 79 4.19 ActiveXObject ............................................................................................... 80 4.20 GetObject....................................................................................................... 80 4.21 VBArray and its members .............................................................................. 80 4.22 Enumertor and its methods ............................................................................. 82 4.23 FileSystemObject and its methods and properties ........................................... 83 4.24 Dictionary and its methods and properties ...................................................... 83 5 References ............................................................................................................. 83 6 Appendix ............................................................................................................... 83 7 Revision history..................................................................................................... 87
1 Introduction
This document lists the differences between JScript and ECMAScript Edition 3 standard. Please send feedback on this document to pratapL ([email protected]).
While all the implementations permit future reserved words to be declared as identifiers, there are some differences. Example:
<script> // test if a word can be declared as var function testdecl(words) { var e; for (var i = 0; i < words.length; i++) { var word = words[i]; try { eval('var ' + word + ';');
document.write('test failed: ' + word + ' is declarable' + '<br>'); } catch(e) {} } } // keywords var keywords = ['break', 'finally', 'switch', 'with', 'in',
// future reserved words var reserved = ['abstract', 'enum', 'export', 'interface', 'long', 'super', 'synchronized', 'class', 'const', 'goto', 'debugger', 'implements', 'protected', 'public']; testdecl(keywords); testdecl(reserved); </script>
'volatile', 'double',
Output: Differences in the set of reserved words that can be declared are as shown below - n indicates that a particular word is not declarable and blank cells indicate that a particular word is declarable.
Declarable? Opera
reserved words abstract enum int short boolean export interface static byte extends
IE
FF
Safari
long super char final native synchronized class float package throws const goto private transient debugger implements protected volatile double import public
n n
Output: IE: taken as a single string. FF: same as IE Opera: same as IE Safari: same as IE IE eats away the \ and the character following it. The s.length will evaluate to 34 (this includes the leading blanks in the second line). FF, Opera and Safari emulate IE.
Example:
<script> function foo() { document.write(arguments); document.write(arguments[0]); eval("arguments = 10;"); document.write(arguments); document.write(arguments[0]); } foo("test"); </script>
Output: IE: [object Object]test[object Object]test FF: [object Object]test10undefined Opera: testtest10undefined Safari: [object Arguments]test10undefined Note: Refer 10.1.6 - arguments is added as a {DontDelete} property to the variable object before the variable instantiations steps (10.1.3) take place. Now, consider the following:
<script> function foo() { document.write(arguments); document.write(arguments[0]); arguments = 10; document.write(arguments); document.write(arguments[0]); } foo(42); </script>
And here is the outputs: IE: [object Object]4210undefined FF: same as IE Opera: 424210undefined Safari: [object Arguments]4210undefined Note: In JScript arguments isnt included in the variable context that is used by the eval, so the evaled assignment isnt actually changing the value of the enclosing functions arguments variable.
Output: IE: IE sees me FF: IE sees meIE can't see me Opera: IE can't see meIE sees me Safari: same as Opera IE incorrectly implements the delete operator when applied to the global object. Attempting to execute delete this.invisibleToIE in the example below produces a runtime error (object doesnt support this action) in IE while in FF delete returns false. The FF behaviour seems correct according to 11.4.1, 10.2.1, and 8.6.2.5 Example:
<script> var __global__ = this; function invisibleToIE() { document.write("IE can't see me"); } __global__.visibleToIE = function() { document.write("IE sees me"); }
Output: IE: runtime error (object doesnt support this action) FF: false Opera: same as FF Safari: same as FF In IE the global object does not inherit from Object.prototype even though its type is object. 15 paragraph 8 seems to imply that the Global Object should inherit from Object.prototype (the value of its [[Prototype]] property is implementation dependent, but what ever it is it must be a built-in prototype and hence must follow the rules of paragraph 8. Of the standard methods of Object.prototype, the only one support by the global object in IE is toString Example:
<script> var __global__ = this; document.write(typeof(__global__) + '<br>'); var f = ['toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable']; for (i = 0; i < f.length; i++) { test(f[i]); } function test(s) { if (__global__[s]) { document.write(s + ' supported' + '<br>'); } } </script>
Output: IE: object toString supported FF: object toString supported toLocaleString supported valueOf supported hasOwnProperty supported ________________________________________________________________________ Draft Page 9 of 87
Output: IE: prints "hellohello" FF: prints hello followed by syntax error (bar is not defined) Opera: prints hello followed by ReferenceError (Reference to undefined variable: bar) Safari: prints hello ________________________________________________________________________ Draft Page 10 of 87
Note: IE treats nested function expressions containing a function name as a function declaration that is scoped to the enclosing function (applying the second bullet rule from 10.1.3 instead of case 3 of the semantics in 13. In the following example the forward reference to x gets resolved in IE, whereas we get a syntax error in FF and TypeError in Opera. Example:
<script> function f(x) { x(); y = function x() {document.write("inner called ")}; document.write(x); document.write(arguments[0]); } document.write("test 4 "); f("param"); </script>
Output: IE: test 4 inner called function x() {document.write("inner called ")}function x() {document.write("inner called ")} FF: test 4 Opera: test 4 Safari: test 4 Here is another example of the same issue:
<script> function foo() { function bar() {} var x = function baz(z) { document.write("baz" + z); if (z) baz(false); }; x(true); // legal; bar(); // legal baz(true); // should be illegal, is legal } foo(); </script>
The function statement bar should add bar to foos variable object. The function expression baz should NOT add baz to foos variable object, but it should be in scope when baz is called, so that it can do the recursive call. Output: IE: baztruebazfalsebaztruebazfalse FF: baztruebazfalse (followed by an error baz not defined) Opera: same as FF ________________________________________________________________________ Draft Page 11 of 87
Safari: same as FF
Output: IE: 1 < 10 == true NaN < 1 == false 1 < Infinity == true "10" < 1 == false 1 < "a" == false "a" < "b" == true FF: same as IE Opera: same as IE Safari: same as IE
} // call with the initial values f1(); f2(); // now modify the values v = 'modified value 1'; o.v = 'modified value 2'; f1(); f2(); </script>
Output: IE: v == value 1 v == value 1 v == modified value 1 v == modified value 1 FF: v == value 1 v == value 2 v == modified value 1 v == modified value 2 Opera: same as IE Safari: same as FF Contrast the above example with the case where the function is defined as a function expression: Example:
<script> var v = 'value 1'; var o = {v: 'value 2'}; var f1 = function () { alert('v == ' + v); }; with (o) { var f2 = function () { alert('v == ' + v); }; } // call with the initial values f1(); f2(); // now modify the values
v = 'modified value 1'; o.v = 'modified value 2'; f1(); f2(); </script>
In this case, there is conformance amongst the 4 implementations. Output: IE, FF, Opera, Safari: v == value 1 v == value 2 v == modified value 1 v == modified value 2
Furthermore, function declarations are not legal in statements (although one might consider a function declaration as syntactically identical to a function expression that includes the optional function name). However, all browser hosted implementations allow function declarations in statements, but do it differently. For e.g. JScript compile time initialises the function in surrounding scope (likewise compile time initialises function expressions binding the identifier in the surrounding scope, instead of the contained scope). FF runtime initialises when control flow reaches the function declaration. Example:
<script> // case 1 var o = false; with ({o : true}) { function f() { return o; } } document.write("FunDecl in with-smt is run time instantiated? " +f() +" (should be: true)"); document.write("<br>"); // case 2 var usebeforedeclare = (typeof fn === 'function'); if (true) { function fn() { return true; } } else { function fn() { return false; } } document.write("FunDecl in if-smt is parse time instantiated? " +usebeforedeclare +" (should be: false)\nThe correct path is taken: " +fn() +" (should be: true)");
document.write("<br>"); // case 3: BRANCH : { break BRANCH; function fnc(){} } document.write("FunDecl in labelled statement is parse time instantiated? " +(typeof fnc === 'function') +" (should be: false)"); document.write("<br>"); // case 4 while (false) function func(){} document.write("FunDecl in while-smt is parse time instantiated? " +(typeof func === 'function')+ " (should be: false)"); document.write("<br>"); // case 5 for ( ; false; ) function funct(){} document.write("FunDecl in for-smt is parse time instantiated? " +(typeof funct === 'function') +" (should be: false)"); document.write("<br>"); // case 6 for(var t in {}) function functi(){} document.write("FunDecl in for..in-smt is parse time instantiated? " +(typeof functi === 'function') +" (should be: false)"); document.write("<br>"); // case 7 try { } catch(e) { function functio(){} } document.write("FunDecl in try..catch-smt is parse time instantiated? " +(typeof functio === 'function') +" (should be: false)"); document.write("<br>"); </script>
Output: IE: FunDecl in with-smt is run time instantiated? false (should be: true) FunDecl in if-smt is parse time instantiated? true (should be: false) The correct path is taken: false (should be: true) FunDecl in labelled statement is parse time instantiated? true (should be: false) FunDecl in while-smt is parse time instantiated? true (should be: false) FunDecl in for-smt is parse time instantiated? true (should be: false) FunDecl in for..in-smt is parse time instantiated? true (should be: false) FunDecl in try..catch-smt is parse time instantiated? true (should be: false) FF: FunDecl in with-smt is run time instantiated? true (should be: true) FunDecl in if-smt is parse time instantiated? false (should be: false) The correct path is taken: true (should be: true) FunDecl in labelled statement is parse time instantiated? false (should be: false) FunDecl in while-smt is parse time instantiated? false (should be: false) FunDecl in for-smt is parse time instantiated? false (should be: false) FunDecl in for..in-smt is parse time instantiated? false (should be: false) FunDecl in try..catch-smt is parse time instantiated? false (should be: false) Opera: Same as IE Safari: No output generated! Note: Refer 2.7 in this document for a discussion on function expressions. JScript uses the definition of the last occurrence of the function.
<script> if (true) { function bar() { document.write("bar1"); } } else { function bar() { document.write("bar2"); } } bar(); function foo() { if (true) { function baz() { document.write("baz1"); } } else { function baz() { document.write("baz2"); } } baz(); }
foo(); </script>
Output: IE: Enumerable properties: shoot cowboy propertyIsEnumerable("toString"): false cowboy hasOwnProperty("toString"): true FF: Enumerable properties: toString shoot cowboy propertyIsEnumerable("toString"): true cowboy hasOwnProperty("toString"): true ________________________________________________________________________ Draft Page 17 of 87
Opera: same as FF Safari: same as FF Note: Refer 15.2.4.7 and 11.13.1, and 8.6.2.2 which say that creating a property on an object gives it an empty set of attributes.
Output: IE: hellohello FF: hello (followed by error x is not defined) Opera: same as FF Safari: same as FF Catch is defined as creating a new object with the caught object as a property and putting the new object at the head of the scope chain. If the caught object is a function, calling it within the catch supplies the head of the scope chain as the this value. The called function can add properties to this object. This implies that for code of this shape:
var x; try { // ... } catch (E) { E();
return x; }
The reference to 'x' within the catch is not necessarily to the local declaration of 'x'; this gives Catch the same performance problems as with. If the call to E above were specified to supply the global object (rather than the head of the scope chain) as the this value, the performance issue evaporates and the catch variable can be treated as a local scoped to the catch clause. Example:
<script> function foo() { this.x = 11; } x = "global.x"; try { throw foo; } catch(e) { document.write(x) // Should print "global.x" e(); document.write(x) // Should add x to e // (Both IE and Firefox modify the global x) } document.write(x); </script> // Should print "global.x".
Output: IE: prints "global.x1111 FF: same as IE Opera: prints "global.x11global.x" Safari: same as Opera
Output: IE: 1,2 1undefined2 1-2 FF: 1,2 1,2 1-2 Opera: same as FF Safari: same as FF
return the length of the resultant array. The returned value of this function call in JScript is undefined. Example:
<script> var a = new Array(1, 2, 3); var l = a.unshift(); document.write(l, " "); document.write(a.length, " "); document.write(a, " "); l = a.unshift(2); document.write(l, " "); document.write(a.length, " "); document.write(a, " "); </script>
Output: IE: undefined 3 1,2,3 undefined 4 2,1,2,3 FF: 3 3 1,2,3 4 4 2,1,2,3 Opera: same as FF Safari: same as FF
Date.prototype.setHours.length Date.prototype.setUTCHours.length Date.prototype.setMonth.length Date.prototype.setUTCMonth.length Date.prototype.setFullYear.length Date.prototype.setUTCFullYear.length RegExp.length Error.length EvalError.length RangeError.length ReferenceError.length SyntaxError.length TypeError.length
4 4 2 2 3 3 2 1 1 1 1 1 1
4 4 2 2 3 3 2 1 1 1 1 1 1
4 4 2 2 3 3 1 3 3 3 3 3 3
4 4 2 2 3 3 2 1 1 1 1 1 1
4 4 2 2 3 3 2 1 1 1 1 1 1
Here is an example that shows a list of length properties that ES3 explicitly calls out.
<script> function test(p, v) { // p: property to test // v: expected value as per ES3; var r = (eval(p) == v); if (r == false) { document.write(p + ' == ' + v + ' : ' + r + '. Actual value: ' + eval(p) + '<br>'); } } test('Object.length', 1); test('Function.length', 1); test('Function.prototype.apply.length', 2); test('Function.prototype.call.length', 1); test('Array.length', 1); test('Array.prototype.length', 0); test('Array.prototype.concat.length', 1); test('Array.prototype.join.length', 1); test('Array.prototype.push.length', 1); test('Array.prototype.slice.length', 2); test('Array.prototype.splice.length', 2); test('Array.prototype.unshift.length', 1); test('String.length', 1); test('String.fromCharCode.length', 1); test('String.prototype.concat.length', 1); test('String.prototype.indexOf.length', 1); test('String.prototype.lastIndexOf.length', 1); test('String.prototype.slice.length', 2); test('String.prototype.split.length', 2); test('String.prototype.substring.length', 2);
test('String.prototype.substr.length', 2); test('Boolean.length', 1); test('Number.length', 1); test('Number.prototype.toFixed.length', 1); test('Number.prototype.toExponential.length', 1); test('Number.prototype.toPrecision.length', 1); test('Math.max.length', 2); test('Math.min.length', 2); test('Date.length', 7); test('Date.UTC.length', 7); test('Date.prototype.setSeconds.length', 2); test('Date.prototype.setUTCSeconds.length', 2); test('Date.prototype.setMinutes.length', 3); test('Date.prototype.setUTCMinutes.length', 3); test('Date.prototype.setHours.length', 4); test('Date.prototype.setUTCHours.length', 4); test('Date.prototype.setMonth.length', 2); test('Date.prototype.setUTCMonth.length', 2); test('Date.prototype.setFullYear.length', 3); test('Date.prototype.setUTCFullYear.length', 3); test('RegExp.length', 2); test('Error.length', 1); test('EvalError.length', 1); test('RangeError.length', 1); test('ReferenceError.length', 1); test('SyntaxError.length', 1); test('TypeError.length', 1); </script>
Output: IE: number.toString() == 123.456 number == 123.456 Exception thrown. RangeError: The precision is out of range FF: number.toString() == 123.456 number == 123.456 number.toPrecision(undefined) == 123.456 Opera: same as FF Safari: same as FF
Example:
<script> document.write('Date.prototype.valueOf() == ' + Date.prototype.valueOf()); </script>
Output: IE: 0 FF: NaN Opera: same as FF Safari: same as FF Note: ES3 15.9.5 says that Date.prototype is itself a Date object whose value is NaN
document.write(a2); </script>
Output: IE: ['zaacbbbcac','z','ac','a','bbb','c'] ['',''] FF: ['zaacbbbcac','z','ac','a',undefined,'c'] ['',undefined] Opera: same as FF Safari: same as IE
IE: /foo/ /foo/ RegExpError: Syntax error in regular expression /foo/ /foo/ //igm /foo/igm RegExpError: Syntax error in regular expression FF: /foo/ /foo/ TypeError: can't supply flags when constructing one RegExp from another /foo/ /foo/ /undefined/gim /foo/gim SyntaxError: invalid regular expression flag p Opera: /foo/ /foo/ TypeError: Statement on line 4: new RegExp cannot be called on both a RegExp and a defined set of flags Backtrace: Line 4 of inline#1 script in file://localhost/D:/jsJavaScript/test.html var r = new RegExp(p, f); Line 14 of inline#1 script in file://localhost/D:/jsJavaScript/test.html test(new RegExp("foo"), "gim"); /foo/ /foo/ //gim SyntaxError: Statement on line 4: RegExp.prototype.compile: syntax error in pattern or string Backtrace: Line 4 of inline#1 script in file://localhost/D:/jsJavaScript/test.html var r = new RegExp(p, f); Line 18 of inline#1 script in file://localhost/D:/jsJavaScript/test.html test("foo", "gimgim"); SyntaxError: Statement on line 4: RegExp.prototype.compile: syntax error in pattern or string Backtrace: Line 4 of inline#1 script in file://localhost/D:/jsJavaScript/test.html var r = new RegExp(p, f); Line 19 of inline#1 script in file://localhost/D:/jsJavaScript/test.html test("foo", "pvl"); Safari: /foo/ /foo/ TypeError: Type error /foo/ /foo/ //gim ________________________________________________________________________ Draft Page 29 of 87
/foo/gim /foo/
by JScript. Example:
<script> var d = new Date("10 July 2001"); var y = d.getYear(); document.write(y + '<br>'); </script>
by JScript. Example:
<script> var d = new Date(+0); d.setYear(95); y = d.getYear(); document.write("setYear: " + y + "
");
Output: IE: setYear: 95 setFullYear: 95 FF: setYear: 95 setFullYear: -1805 Opera: same as FF Safari: same as FF
var x = 0x8000000000000800; document.write(x, " "); var y = 9223372036854777856; document.write(y); </script> // same as above
Output: IE: 9223372036854777000 9223372036854777000 FF: 9223372036854778000 9223372036854778000 Opera: same as FF Safari: same as FF
Output: IE: object FF: function Opera: same as FF Safari: same as FF The above example as extended below does not work in IE. Example:
<script> alert(typeof(window.alert)); var a = window.alert; a.apply(null, [45]); </script>
Output: IE: Object Line: 4 Error: object doesnt support this property or method ________________________________________________________________________ Draft Page 32 of 87
Output: IE: pizza.bc = bc pizza.bb = bb pizza.ba = ba pizza.da = da pizza.db = db pizza.dc = dc pizza.pa = pa pizza.pb = pb pizza.pc = pc FF: pizza.pa = pa pizza.pb = pb pizza.pc = pc pizza.ba = ba pizza.bb = bb pizza.bc = bc pizza.da = da pizza.db = db pizza.dc = dc Opera: Same as FF Safari: Same as FF
</script>
As per 13.1.1, the two calls to foo() produce a function from the same FunctionBody, so they are equated and the resulting function objects can be joined. By 13.2 items 1, 13, and 14, the two uses of bar create two objects that are joined: they have different internal properties, but act as "one object"; side effects on one are visible on the other. IE, FF, Opera and Safari currently show "3", but an implementation could show "4" and still be compliant.
Example:
<script> var sum = eval("1 + 2"); alert(sum); // Returns 3
var myeval = eval; try { sum = myeval("1 + 2"); alert(sum); } catch (e) { alert("indirect eval not supported!"); } </script>
Ouput: IE: alerts 3 twice FF: same as IE Opera: alerts 3 first, and then alerts indirect eval not supported Safari: same as IE
Output: IE: alerts 0, 0, 9, 9 FF: same as IE Opera: alerts 8, 8, 11, 11 Safari: same as FF
Output: IE: 45 FF: 42 Opera: 43 Safari: 45 The following example of a deliberately poorly formatted script further illustrates the differences. Example:
<script> function foo() { document.write( ( // this is a comment function (/* this is another comment */ n) { return n; })(4) ); } document.write(foo); </script>
function foo() { document.write( ( // this is a comment function (/* this is another comment */ n) { return n; })(4) ); } FF: function foo() { document.write((function (n) {return n;})(4)); } Opera: function foo() { document.write((function (n) { return n; } )(4)); } Safari: function foo() { document.write((function (n) { return n; })(4)); } Further, consider the following example with nested functions: Example:
<script> function foo() { var i = 0; for (var n = 0; n < 10; n++) { i++; } function bar() { var b = 0; } } document.write(foo.toString()); </script>
Output: IE: function foo() { var i = 0; for (var n = 0; n < 10; n++) { i++; } function bar() { var b = 0; }} FF: same as IE Opera: function foo() { function bar() { var b = 0; } var i = 0; for (var n = 0;n < 10;n++) { i++; } } Safari: function foo() { var i = 0; for (n = 0; n < 10; n++) { i++; } function bar() { var b = 0; } }
Finally, note that a function defined by the Function constructor does not have a function name. However, for example below, both IE and FF make it appear that the function is named anonymous. Example:
<script> document.write(new Function()); </script>
Output: IE: function anonymous() { } FF: same as IE Opera: function () { } Safari: function anonymous() { ; }
Output: IE: [object] FF: [object HTMLDocument] Opera: same as FF Safari: same as FF
</script>
Output: IE: runtime error (object doesnt support this property or method) FF: [object HTMLDocument] Opera: same as FF Safari: same as FF
var a = new Array(); a.push(n); a.push(d); a.push(d); a.push(s); document.write(a.toString() + "<br>"); document.write(a.toLocaleString() + "<br>"); </script>
Output: IE:
123456789,Fri Jul 13 01:13:45 UTC+0530 2007,Fri Jul 13 01:13:45 UTC+0530 2007,hello world 123,456,789.00, Friday, July 13, 2007 1:13:45 AM, Friday, July 13, 2007 1:13:45 AM, hello world
FF:
123456789,Fri Jul 13 2007 01:14:50 GMT+0530 (India Standard Time),Fri Jul 13 2007 01:14:50 GMT+0530 (India Standard
Time),hello world 123,456,789,Friday, July 13, 2007 1:14:50 AM,Friday, July 13, 2007 1:14:50 AM,hello world
Opera
123456789,Fri, 13 Jul 2007 01:16:07 GMT+0530,Fri, 13 Jul 2007 01:16:07 GMT+0530,hello world 123456789,7/13/2007 1:16:07 AM,7/13/2007 1:16:07 AM,hello world
Safari
123456789,Fri Jul 13 2007 01:16:24 GMT+0530 (India Standard Time),Fri Jul 13 2007 01:16:24 GMT+0530 (India Standard Time),hello world 123456789,Friday, July 13, 2007 01:16:24,Friday, July 13, 2007 01:16:24,hello world
Output: IE: 16, NaN FF, 16, -16 Opera: same as FF Safari: same as IE Note: This is actually according to spec for IE. FF deviates from the spec: 15.7.1.1 says that the conversion is defined by To Number (9.3 and 9.3.1). 9.3.1 says that strings that can not be recognized by the grammar given in that section produce NaN as the ToValue result. The grammar does not recognize negative hex strings, so NaN is the correct result. This is an example, of variation among implementations where IE follows the ES3 spec. and some other implementations arent.
// try an invalid radix try { document.write('val.toString(undefined) == ' + val.toString(undefined) + '<br>'); } catch(e) { document.write('Invalid Radix Error: ' + e.name + ': ' + e.message + '<br>'); } </script>
Output: IE: val.toString() == 42 val.toString(2) == 101010 val.toString(8) == 52 val.toString(16) == 2a val.toString(36) == 16 Invalid Radix Error: TypeError: Invalid procedure call or argument val.toString() == 42 Invalid Radix Error: TypeError: Invalid procedure call or argument FF: val.toString() == 42 val.toString(2) == 101010 val.toString(8) == 52 val.toString(16) == 2a val.toString(36) == 16 Invalid Radix Error: Error: illegal radix 100 val.toString() == 42 Invalid Radix Error: Error: illegal radix 0 Opera: val.toString() == 42 val.toString(2) == 101010 val.toString(8) == 52 val.toString(16) == 2a val.toString(36) == 16 val.toString(100) == 42 val.toString() == 42 val.toString(undefined) == 42 Safari: same as Opera.
Output: IE: val1.toString() == 12 val1.toLocaleString() == 12.00 val2.toString() == 123456789 val2.toLocaleString() == 123,456,789.00 FF: val1.toString() == 12 val1.toLocaleString() == 12 val2.toString() == 123456789 val2.toLocaleString() == 123,456,789 Opera: val1.toString() == 12 val1.toLocaleString() == 12 val2.toString() == 123456789 val2.toLocaleString() == 123456789 Safari: same as Opera
Example:
<script> var number = 123.456; document.write('number.toFixed(2) == ' + number.toFixed(2) + '<br>'); // check for RangeError for fractionDigits > 20 try { document.write('number.toFixed(21) == ' + number.toFixed(21) + '<br>'); document.write('Test failed. Should have thrown a RangeError.' + '<br>'); } catch(e) { document.write('Expected Exception thrown. ' + e.name + ': ' + e.message + '<br>'); try { document.write('Exception is a RangeError: ' + (e instanceof RangeError) + '<br>'); } catch (e2) { document.write('Error using instanceof ' + e2.name + ': ' + e2.message + '<br>'); } } // check for RangeError for fractionDigits < 0 try { document.write('number.toFixed(-1) == ' + number.toFixed(-1) + '<br>'); document.write('Test failed. Should have thrown a RangeError.' + '<br>'); } catch (e) { document.write('Expected Exception thrown. ' + e.name + ': ' + e.message + '<br>'); try { document.write('Exception is a RangeError: ' + (e instanceof RangeError) + '<br>'); } catch (e2) { document.write('Error using instanceof ' + e2.name + ': ' + e2.message + '<br>'); } } </script>
Expected Exception thrown. RangeError: The number of fractional digits is out of range Exception is a RangeError: true Expected Exception thrown. RangeError: The number of fractional digits is out of range Exception is a RangeError: true FF: number.toFixed(2) == 123.46 number.toFixed(21) == 123.456000000000003069545 Test failed. Should have thrown a RangeError. number.toFixed(-1) == 120 Test failed. Should have thrown a RangeError. Opera: number.toFixed(2) == 123.46 Expected Exception thrown. RangeError: Statement on line 7: Number.prototype.toFixed: too many decimal places requested Backtrace: Line 7 of inline#1 script in file://localhost/d:/jsjavaScript/test.html document.write("number.toFixed(21) == " + number.toFixed(21) + " "); Exception is a RangeError: true Expected Exception thrown. RangeError: Statement on line 22: Number.prototype.toFixed: too many decimal places requested Backtrace: Line 22 of inline#1 script in file://localhost/d:/jsjavaScript/test.html document.write("number.toFixed(-1) == " + number.toFixed(- 1) + " "); Exception is a RangeError: true Safari: number.toFixed(2) == 123.46 Expected Exception thrown. RangeError: toFixed() digits argument must be between 0 and 20 Exception is a RangeError: true Expected Exception thrown. RangeError: toFixed() digits argument must be between 0 and 20 Exception is a RangeError: true
document.write('number.toExponential(2) == ' + number.toExponential(2) + '<br>'); // check for RangeError for fractionDigits > 20 try { document.write('number.toExponential(21) == ' + number.toExponential(21) + '<br>'); document.write('Test failed. Should have thrown a RangeError.' + '<br>'); } catch (e) { document.write('Expected Exception thrown. ' + e.name + ': ' + e.message + '<br>'); try { document.write('Exception is a RangeError: ' + (e instanceof RangeError) + '<br>'); } catch (e2) { document.write('Error using instanceof ' + e2.name + ': ' + e2.message + '<br>'); } } // check for RangeError for fractionDigits < 0 try { document.write('number.toExponential(-1) == ' + number.toExponential(-1) + '<br>'); document.write('Test failed. Should have thrown a RangeError.' + '<br>'); } catch (e) { document.write('Expected Exception thrown. ' + e.name + ': ' + e.message + '<br>'); try { document.write('Exception is a RangeError: ' + (e instanceof RangeError) + '<br>'); } catch (e2) { document.write('Error using instanceof ' + e2.name + ': ' + e2.message + '<br>'); } } document.write('number.toExponential(undefined) == ' + number.toExponential(undefined) + '<br>'); document.write('number.toExponential() == ' + number.toExponential() + '<br>'); </script>
IE: number.toExponential(2) == 1.23e+2 Expected Exception thrown. RangeError: The number of fractional digits is out of range Exception is a RangeError: true Expected Exception thrown. RangeError: The number of fractional digits is out of range Exception is a RangeError: true number.toExponential(undefined) == 1e+2 number.toExponential() == 1.23456e+2 FF: number.toExponential(2) == 1.23e+2 number.toExponential(21) == 1.234560000000000030695e+2 Test failed. Should have thrown a RangeError. Expected Exception thrown. RangeError: precision -1 out of range Exception is a RangeError: true number.toExponential(undefined) == 1.23456e+2 number.toExponential() == 1.23456e+2 Opera: number.toExponential(2) == 1.23e+2 Expected Exception thrown. RangeError: Statement on line 7: Number.prototype.toExponential: too many decimal places requested Backtrace: Line 7 of inline#1 script in file://localhost/D:/jsJavaScript/test.html document.write("number.toExponential(21) == " + number.toExponential(21) + " "); Exception is a RangeError: true Expected Exception thrown. RangeError: Statement on line 22: Number.prototype.toExponential: too many decimal places requested Backtrace: Line 22 of inline#1 script in file://localhost/D:/jsJavaScript/test.html document.write("number.toExponential(-1) == " + number.toExponential(- 1) + " "); Exception is a RangeError: true number.toExponential(undefined) == 1.23456e+2 number.toExponential() == 1.23456e+2 Safari: number.toExponential(2) == 1.23e+2 Expected Exception thrown. RangeError: toExponential() argument must between 0 and 20 Exception is a RangeError: true Expected Exception thrown. RangeError: toExponential() argument must between 0 and 20 Exception is a RangeError: true number.toExponential(undefined) == 1.23456e+2 number.toExponential() == 1.23456e+2
Output: IE: Throws a RangeError if fractionDigits is greater than 21, as well as if it less than 1. FF: Does not throw a RangeError if fractionDigits is greater than 21, but does if it is less than 1. Opera: same as IE Safari: same as IE
document.write('Date.parse("' + datestring + '") == ' + Date.parse(datestring) + '<br>'); document.write('<br>'); } // Short dates can use either a "/" or "-" date separator, but // must follow the month/day/year format, for example "7/10/95". test("7/10/95"); test("7-10-95"); // Long dates of the form "July 10 1995" can be given with the // year, month, and day in any order, and the year in 2-digit or // 4-digit form. In the 2-digit form, the year must be greater // than or equal to 70. test("July 10 1995"); test("10 July 1995"); test("10 1995 July"); test("10 95 July"); // Both commas and spaces are treated as delimiters. Multiple // delimiters are permitted. test("July,10 1995"); test("July,,10 ,,1995"); // Any text inside parentheses is treated as a comment. These // parentheses may be nested. test("July (monthOfYear) 10 (dayOfMonth) 1995 (year)"); // Month and day names must have two or more characters. Two // character names that are not unique are resolved as the // last match. For example, "Ju" is resolved as July, not June. test("Ju (monthOfYear) 10 (dayOfMonth) 1995 (year)"); // The stated day of the week is ignored if it is incorrect // given the remainder of the supplied date. For example, // "Tuesday July 10 1995" is accepted and parsed even though // that date actually falls on a Monday. The resulting Date // object represents "Monday July 10 1995". test("Tuesday July 10 1995"); // JScript handles all standard time zones, as well as UTC // and GMT. test("10, July, 1995, 11:22, PM, PST"); test("10, July, 1995, 11:22, PM, UTC"); test("10, July, 1995, 11:22, PM, GMT"); // Hours, minutes, and seconds are separated by colons, // although all need not be specified. "10:", "10:11", // and "10:11:12" are all valid. test("10, July, 1995, 11:, PM, PST"); test("10, July, 1995, 11:22, PM, UTC"); test("10, July, 1995, 11:22:00, PM, GMT");
// If the 24-hour clock is used, it is an error to specify // "PM" for times later than 12 noon. For e.g., "23:15 PM" // is an error. test("10, July, 1995, 23:15, PM, PST"); // A string containing an invalid date is an error. // For e.g., a string containing two years or two months is // an error. test("10, July, July 1995"); test("10, July, 1995 1995"); test("10, July, 1995, 11:22:00, PM, GMT GMT"); </script>
Output: IE: new Date("7/10/95") == Mon Jul 10 00:00:00 UTC+0530 1995 Date.parse("7/10/95") == 805314600000 new Date("7-10-95") == Mon Jul 10 00:00:00 UTC+0530 1995 Date.parse("7-10-95") == 805314600000 new Date("July 10 1995") == Mon Jul 10 00:00:00 UTC+0530 1995 Date.parse("July 10 1995") == 805314600000 new Date("10 July 1995") == Mon Jul 10 00:00:00 UTC+0530 1995 Date.parse("10 July 1995") == 805314600000 new Date("10 1995 July") == Mon Jul 10 00:00:00 UTC+0530 1995 Date.parse("10 1995 July") == 805314600000 new Date("10 95 July") == Mon Jul 10 00:00:00 UTC+0530 1995 Date.parse("10 95 July") == 805314600000 new Date("July,10 1995") == Mon Jul 10 00:00:00 UTC+0530 1995 Date.parse("July,10 1995") == 805314600000 new Date("July,,10 ,,1995") == Mon Jul 10 00:00:00 UTC+0530 1995 Date.parse("July,,10 ,,1995") == 805314600000 new Date("July (monthOfYear) 10 (dayOfMonth) 1995 (year)") == Mon Jul 10 00:00:00 UTC+0530 1995 Date.parse("July (monthOfYear) 10 (dayOfMonth) 1995 (year)") == 805314600000 new Date("Ju (monthOfYear) 10 (dayOfMonth) 1995 (year)") == Mon Jul 10 00:00:00 UTC+0530 1995 Date.parse("Ju (monthOfYear) 10 (dayOfMonth) 1995 (year)") == 805314600000 ________________________________________________________________________ Draft Page 52 of 87
new Date("Tuesday July 10 1995") == Mon Jul 10 00:00:00 UTC+0530 1995 Date.parse("Tuesday July 10 1995") == 805314600000 new Date("10, July, 1995, 11:22, PM, PST") == Tue Jul 11 12:52:00 UTC+0530 1995 Date.parse("10, July, 1995, 11:22, PM, PST") == 805447320000 new Date("10, July, 1995, 11:22, PM, UTC") == Tue Jul 11 04:52:00 UTC+0530 1995 Date.parse("10, July, 1995, 11:22, PM, UTC") == 805418520000 new Date("10, July, 1995, 11:22, PM, GMT") == Tue Jul 11 04:52:00 UTC+0530 1995 Date.parse("10, July, 1995, 11:22, PM, GMT") == 805418520000 new Date("10, July, 1995, 11:, PM, PST") == Tue Jul 11 12:30:00 UTC+0530 1995 Date.parse("10, July, 1995, 11:, PM, PST") == 805446000000 new Date("10, July, 1995, 11:22, PM, UTC") == Tue Jul 11 04:52:00 UTC+0530 1995 Date.parse("10, July, 1995, 11:22, PM, UTC") == 805418520000 new Date("10, July, 1995, 11:22:00, PM, GMT") == Tue Jul 11 04:52:00 UTC+0530 1995 Date.parse("10, July, 1995, 11:22:00, PM, GMT") == 805418520000 new Date("10, July, 1995, 23:15, PM, PST") == NaN Date.parse("10, July, 1995, 23:15, PM, PST") == NaN new Date("10, July, July 1995") == NaN Date.parse("10, July, July 1995") == NaN new Date("10, July, 1995 1995") == NaN Date.parse("10, July, 1995 1995") == NaN new Date("10, July, 1995, 11:22:00, PM, GMT GMT") == NaN Date.parse("10, July, 1995, 11:22:00, PM, GMT GMT") == NaN FF: new Date("7/10/95") == Mon Jul 10 1995 00:00:00 GMT+0530 (India Standard Time) Date.parse("7/10/95") == 805314600000 new Date("7-10-95") == Invalid Date Date.parse("7-10-95") == NaN new Date("July 10 1995") == Mon Jul 10 1995 00:00:00 GMT+0530 (India Standard Time) Date.parse("July 10 1995") == 805314600000
new Date("10 July 1995") == Mon Jul 10 1995 00:00:00 GMT+0530 (India Standard Time) Date.parse("10 July 1995") == 805314600000 new Date("10 1995 July") == Mon Jul 10 1995 00:00:00 GMT+0530 (India Standard Time) Date.parse("10 1995 July") == 805314600000 new Date("10 95 July") == Mon Jul 10 1995 00:00:00 GMT+0530 (India Standard Time) Date.parse("10 95 July") == 805314600000 new Date("July,10 1995") == Mon Jul 10 1995 00:00:00 GMT+0530 (India Standard Time) Date.parse("July,10 1995") == 805314600000 new Date("July,,10 ,,1995") == Mon Jul 10 1995 00:00:00 GMT+0530 (India Standard Time) Date.parse("July,,10 ,,1995") == 805314600000 new Date("July (monthOfYear) 10 (dayOfMonth) 1995 (year)") == Mon Jul 10 1995 00:00:00 GMT+0530 (India Standard Time) Date.parse("July (monthOfYear) 10 (dayOfMonth) 1995 (year)") == 805314600000 new Date("Ju (monthOfYear) 10 (dayOfMonth) 1995 (year)") == Mon Jul 10 1995 00:00:00 GMT+0530 (India Standard Time) Date.parse("Ju (monthOfYear) 10 (dayOfMonth) 1995 (year)") == 805314600000 new Date("Tuesday July 10 1995") == Mon Jul 10 1995 00:00:00 GMT+0530 (India Standard Time) Date.parse("Tuesday July 10 1995") == 805314600000 new Date("10, July, 1995, 11:22, PM, PST") == Tue Jul 11 1995 12:52:00 GMT+0530 (India Standard Time) Date.parse("10, July, 1995, 11:22, PM, PST") == 805447320000 new Date("10, July, 1995, 11:22, PM, UTC") == Tue Jul 11 1995 04:52:00 GMT+0530 (India Standard Time) Date.parse("10, July, 1995, 11:22, PM, UTC") == 805418520000 new Date("10, July, 1995, 11:22, PM, GMT") == Tue Jul 11 1995 04:52:00 GMT+0530 (India Standard Time) Date.parse("10, July, 1995, 11:22, PM, GMT") == 805418520000 new Date("10, July, 1995, 11:, PM, PST") == Tue Jul 11 1995 12:30:00 GMT+0530 (India Standard Time) Date.parse("10, July, 1995, 11:, PM, PST") == 805446000000 ________________________________________________________________________ Draft Page 54 of 87
new Date("10, July, 1995, 11:22, PM, UTC") == Tue Jul 11 1995 04:52:00 GMT+0530 (India Standard Time) Date.parse("10, July, 1995, 11:22, PM, UTC") == 805418520000 new Date("10, July, 1995, 11:22:00, PM, GMT") == Tue Jul 11 1995 04:52:00 GMT+0530 (India Standard Time) Date.parse("10, July, 1995, 11:22:00, PM, GMT") == 805418520000 new Date("10, July, 1995, 23:15, PM, PST") == Invalid Date Date.parse("10, July, 1995, 23:15, PM, PST") == NaN new Date("10, July, July 1995") == Invalid Date Date.parse("10, July, July 1995") == NaN new Date("10, July, 1995 1995") == Invalid Date Date.parse("10, July, 1995 1995") == NaN new Date("10, July, 1995, 11:22:00, PM, GMT GMT") == Tue Jul 11 1995 04:52:00 GMT+0530 (India Standard Time) Date.parse("10, July, 1995, 11:22:00, PM, GMT GMT") == 805418520000 Opera: new Date("7/10/95") == Mon, 10 Jul 1995 00:00:00 GMT+0530 Date.parse("7/10/95") == 805314600000 new Date("7-10-95") == Sat, 07 Oct 1995 00:00:00 GMT+0530 Date.parse("7-10-95") == 813004200000 new Date("July 10 1995") == Mon, 10 Jul 1995 00:00:00 GMT+0530 Date.parse("July 10 1995") == 805314600000 new Date("10 July 1995") == Mon, 10 Jul 1995 00:00:00 GMT+0530 Date.parse("10 July 1995") == 805314600000 new Date("10 1995 July") == Mon, 10 Jul 1995 00:00:00 GMT+0530 Date.parse("10 1995 July") == 805314600000 new Date("10 95 July") == Tue, 10 Jul 2007 00:00:00 GMT+0530 Date.parse("10 95 July") == 1184005800000 new Date("July,10 1995") == Mon, 10 Jul 1995 00:00:00 GMT+0530 Date.parse("July,10 1995") == 805314600000 new Date("July,,10 ,,1995") == Mon, 10 Jul 1995 00:00:00 GMT+0530 Date.parse("July,,10 ,,1995") == 805314600000 ________________________________________________________________________ Draft Page 55 of 87
new Date("July (monthOfYear) 10 (dayOfMonth) 1995 (year)") == Mon, 10 Jul 1995 00:00:00 GMT+0530 Date.parse("July (monthOfYear) 10 (dayOfMonth) 1995 (year)") == 805314600000 new Date("Ju (monthOfYear) 10 (dayOfMonth) 1995 (year)") == Thu, 10 Aug 1995 00:00:00 GMT+0530 Date.parse("Ju (monthOfYear) 10 (dayOfMonth) 1995 (year)") == 807993000000 new Date("Tuesday July 10 1995") == Mon, 10 Jul 1995 00:00:00 GMT+0530 Date.parse("Tuesday July 10 1995") == 805314600000 new Date("10, July, 1995, 11:22, PM, PST") == Mon, 10 Jul 1995 23:22:00 GMT+0530 Date.parse("10, July, 1995, 11:22, PM, PST") == 805398720000 new Date("10, July, 1995, 11:22, PM, UTC") == Tue, 11 Jul 1995 04:52:00 GMT+0530 Date.parse("10, July, 1995, 11:22, PM, UTC") == 805418520000 new Date("10, July, 1995, 11:22, PM, GMT") == Tue, 11 Jul 1995 04:52:00 GMT+0530 Date.parse("10, July, 1995, 11:22, PM, GMT") == 805418520000 new Date("10, July, 1995, 11:, PM, PST") == Mon, 10 Jul 1995 23:00:00 GMT+0530 Date.parse("10, July, 1995, 11:, PM, PST") == 805397400000 new Date("10, July, 1995, 11:22, PM, UTC") == Tue, 11 Jul 1995 04:52:00 GMT+0530 Date.parse("10, July, 1995, 11:22, PM, UTC") == 805418520000 new Date("10, July, 1995, 11:22:00, PM, GMT") == Tue, 11 Jul 1995 04:52:00 GMT+0530 Date.parse("10, July, 1995, 11:22:00, PM, GMT") == 805418520000 new Date("10, July, 1995, 23:15, PM, PST") == Mon, 10 Jul 1995 23:15:00 GMT+0530 Date.parse("10, July, 1995, 23:15, PM, PST") == 805398300000 new Date("10, July, July 1995") == Mon, 10 Jul 1995 00:00:00 GMT+0530 Date.parse("10, July, July 1995") == 805314600000 new Date("10, July, 1995 1995") == Mon, 10 Jul 1995 00:00:00 GMT+0530 Date.parse("10, July, 1995 1995") == 805314600000 new Date("10, July, 1995, 11:22:00, PM, GMT GMT") == Tue, 11 Jul 1995 04:52:00 GMT+0530 Date.parse("10, July, 1995, 11:22:00, PM, GMT GMT") == 805418520000 Safari: new Date("7/10/95") == Mon Jul 10 1995 00:00:00 GMT+0530 (India Standard Time) ________________________________________________________________________ Draft Page 56 of 87
Date.parse("7/10/95") == 805314600000 new Date("7-10-95") == Invalid Date Date.parse("7-10-95") == NaN new Date("July 10 1995") == Mon Jul 10 1995 00:00:00 GMT+0530 (India Standard Time) Date.parse("July 10 1995") == 805314600000 new Date("10 July 1995") == Mon Jul 10 1995 00:00:00 GMT+0530 (India Standard Time) Date.parse("10 July 1995") == 805314600000 new Date("10 1995 July") == Invalid Date Date.parse("10 1995 July") == NaN new Date("10 95 July") == Invalid Date Date.parse("10 95 July") == NaN new Date("July,10 1995") == Mon Jul 10 1995 00:00:00 GMT+0530 (India Standard Time) Date.parse("July,10 1995") == 805314600000 new Date("July,,10 ,,1995") == Invalid Date Date.parse("July,,10 ,,1995") == NaN new Date("July (monthOfYear) 10 (dayOfMonth) 1995 (year)") == Mon Jul 10 1995 00:00:00 GMT+0530 (India Standard Time) Date.parse("July (monthOfYear) 10 (dayOfMonth) 1995 (year)") == 805314600000 new Date("Ju (monthOfYear) 10 (dayOfMonth) 1995 (year)") == Invalid Date Date.parse("Ju (monthOfYear) 10 (dayOfMonth) 1995 (year)") == NaN new Date("Tuesday July 10 1995") == Mon Jul 10 1995 00:00:00 GMT+0530 (India Standard Time) Date.parse("Tuesday July 10 1995") == 805314600000 new Date("10, July, 1995, 11:22, PM, PST") == Invalid Date Date.parse("10, July, 1995, 11:22, PM, PST") == NaN new Date("10, July, 1995, 11:22, PM, UTC") == Invalid Date Date.parse("10, July, 1995, 11:22, PM, UTC") == NaN new Date("10, July, 1995, 11:22, PM, GMT") == Invalid Date Date.parse("10, July, 1995, 11:22, PM, GMT") == NaN
new Date("10, July, 1995, 11:, PM, PST") == Invalid Date Date.parse("10, July, 1995, 11:, PM, PST") == NaN new Date("10, July, 1995, 11:22, PM, UTC") == Invalid Date Date.parse("10, July, 1995, 11:22, PM, UTC") == NaN new Date("10, July, 1995, 11:22:00, PM, GMT") == Invalid Date Date.parse("10, July, 1995, 11:22:00, PM, GMT") == NaN new Date("10, July, 1995, 23:15, PM, PST") == Invalid Date Date.parse("10, July, 1995, 23:15, PM, PST") == NaN new Date("10, July, July 1995") == Invalid Date Date.parse("10, July, July 1995") == NaN new Date("10, July, 1995 1995") == Invalid Date Date.parse("10, July, 1995 1995") == NaN new Date("10, July, 1995, 11:22:00, PM, GMT GMT") == Invalid Date Date.parse("10, July, 1995, 11:22:00, PM, GMT GMT") == NaN
Output: IE: 788918400000 FF: same as IE Opera: syntax error Safari: NaN
Example:
<script> var d = new Date("4 July 1776"); document.write(d.toString()); </script>
Output: IE: Thu Jul 4 00:00:00 UTC+0530 1776 FF: Thu Jul 04 1776 00:00:00 GMT+0530 (India Standard Time) Opera: Thu, 04 Jul 1776 00:00:00 GMT+0530 Safari: same as FF
Output: IE: Mon Jul 10 1995 FF: same as IE Opera: Mon, 10 Jul 1995 Safari: same as IE
Output: IE: 00:00:00 UTC+0530 FF: 00:00:00 GMT+0530 (India Standard Time) Opera: 00:00:00 GMT+0530 Safari: same as FF ________________________________________________________________________ Draft Page 59 of 87
Output: IE: Monday, July 10, 1995 12:00:00 AM FF: same as IE Opera: 7/10/1995 12:00:00 AM Safari: Monday, July 10, 1995 00:00:00
Output: IE: Monday, July 10, 1995 FF: same as IE Opera: 7/10/1995 Safari: same as IE
Output: IE: 12:00:00 AM FF: same as IE Opera: same as IE ________________________________________________________________________ Draft Page 60 of 87
Safari: 00:00:00
Output: IE: Sun, 9 Jul 1995 18:30:00 UTC FF: Sun, 09 Jul 1995 18:30:00 GMT Opera: same as FF Safari: same as FF
Output: IE: // // /// FF: /(?:)/ /undefined/ /\// Opera: same as IE Safari: same as IE Furthermore, ES3 does not state the order in which flags must be concatenated into the final string. Example:
<script> document.write(new RegExp('foo', 'mgi').toString() + '<br>'); </script>
Output: IE: e.message: e.message: undefined FF: same as IE Opera: e.message: Generic error e.message: undefined Safari: e.message: Unknown error e.message: Unknown error
Output: IE: e.toString(): [object Error] e.toString(): [object Error] e.toString(): [object Error] FF: e.toString(): Error e.toString(): Error: undefined e.toString(): Error: Complex error Opera: ________________________________________________________________________ Draft Page 63 of 87
e.toString(): [Error: name: Error message: Generic error ] e.toString(): [Error: name: Error ] e.toString(): [Error: name: Error message: Complex error ] Safari: e.toString(): Error: Unknown error e.toString(): Error: Unknown error e.toString(): Error: Complex error
Output: IE: the empty string in each case FF: same as IE Opera: Use of eval as a value Illegal manipulation of array or string length Undefined variable or property Mis-constructed program text Incorrect value to a primitive operation Generic error in a URI Safari: EvalError RangeError ReferenceError SyntaxError TypeError URIError
3.39 Errors: 16
ES3 states that An implementation may provide additional types, values, objects, properties, and functions beyond those described in this specification. This may cause constructs (such as looking up a variable in the global scope) to have implementationdefined behaviour instead of throwing an error (such as ReferenceError). This can hinder interoperability. Example:
<script> var x = {}; x.__proto__ = 3; document.write(x.__proto__); </script>
Output: IE: 3 FF: [object Object] Opera: same as IE Safari: same as IE Note that in this case the user defined __proto__ property clashes with the property of the same name that FF adds.
4 JScript Extensions
4.1 debugger statement
JScript recognizes debugger as a statement, and treats it as a request for a breakpoint. Example:
<script> debugger; </script>
Output: IE: invokes and jumps into a script debugger (if more than one such debugger is available on the system, then the user is given the option to choose). FF: no-op; however, jumps into FireBug iff installed. Opera: no-op Safari; same as Opera
Example:
<script> @cc_on // turn condition compilation ON @set @foo = 0; @if (@foo == 0) { document.write(@foo); } @end @set @foo = 1; @if (@foo == 0) { document.write("unreachable!"); } @else { document.write(@foo); } @end @set @foo = 2; @if (@foo == 0) { document.write("unreachable!"); } @elif (@foo == 2) { document.write(@foo); } @else { document.write("still unreachable!"); } @end document.write("<br>"); // the following are the pre-defined conditionalcompilation // variables available to the JScript programmer. var ccvars = [@_win32, // true if running on a Win32. @_win16, // true if running on a Win16. @_mac, // true if running on an Mac. @_alpha, // true if running on a DECAlpha proc. @_x86, // true if running on an Intel proc. @_mc680x0, // true if running on a Motorola 680x0 // proc. @_PowerPC, // true if running on a Motorola // PowerPC proc. @_win64, // true if running on Win64 @_ia64, // true if running on IA64 proc @_amd64, // true if running on AMD64 proc @_unix, // true if running on HP or Sparc @_sparc, // true if running on Sparc @_hp, // true if running on HP @_microsoft, // always true
// // // // // // //
always true. contains the build number of the JScript scripting engine. contains the JScript version number in major.minor format.
Output: IE: prints 012 true NaN NaN NaN true NaN NaN NaN NaN NaN NaN NaN NaN true true 5730 5.7 FF: syntax error (after the @cc_on directive). Opera: syntax error Safari: conditional compilation is not supported but no error is reported. It is recommended that conditional compilation code be placed within comments, so that hosts that do not understand conditional compilation will ignore it.
File: bar.html
<html> <script> function e1(x, s) { return eval(s) } function e2(x, s) { return top.eval(s) } </script> </html>
Output: IE: displays "e param" followed by "foo param" FF: displays "e param" followed by "e param" (a bug as per Brendan) Opera: displays "e param" (also a bug). Safari: same as FF In IE we maintain 1 script engine per document. So, in this case, there are 2 script engines in existence - one in the iframe's document, and one in the parent's document. When we do an eval(s) (in bar.html), the eval executes in the iframe's script engine. When we do a top.eval(s), the eval executes in the parent document's script engine. Hence, they bind to different scopes.
In bar.html, when we execute eval(s) the value of 's' is from the scope of the 'function e'; however, when we execute top.eval(s) the value of 's' is from the scope of 'function foo'. If you view the stack of activations as a single engine's runtime state, instead of split across two engines, it becomes as follows: for o.eval(s), find the nearest activation of a function scoped by o from the top of (single) stack, and use that activation as dynamic scope.
Output: IE: compiles fine FF: syntax error Opera: syntax error Safari: syntax error JScript permits special syntax to declare event handlers (using ::). There is no syntax to raise an event, however. This can typically be used for VBScript-style event binding on named host objects. Example:
<script> function window::onfocus() { document.write("window has focus"); } /* Here is an eventhandler for the event "bar" on a "foo". function foo(){} function foo::bar() {}
*/ </script>
Output: IE: displays window has focus FF: gives a syntax error for this code. Opera: same as FF Safari: same as FF JScript also supports unnamed function expressions. Example:
<script> function(){} </script>
Output: IE: no error FF: same as IE Opera: Syntax error Safari: same as IE
function. The caller property is only defined for a function while that function is executing. If the function is called from the top level of a JScript program, caller contains null. If the caller property is used in a string context, the result is the same as functionName.toString, that is, the decompiled text of the function is displayed. The functionName object is the name of any executing function. Example:
<script> function foo() { document.write(foo.caller); document.write('<br>'); if (foo.caller != null) { foo.caller(0); } } foo(); bar(1);
Output: IE: prints null function bar(x) { if (x == 1) { foo(); } else { document.write("done"); document.write(" "); } } done FF: same as JScript Opera: prints, undefined undefined Safari: Same as JScript
4.7 RegExp.index
JScript adds this property to the RegExp constructor even for non global regular expressions, and sets it value to the index in the string of the last match. The property has the attributes { DontEnum, DontDelete, ReadOnly }. Example:
<script> var s = "Able was I ere I saw Elba."; var re = /((\w+) (\w+) (\w+) (\w+) (\w+) (\w+) (\w+)(.*))/; re.exec(s); document.write('RegExp.index == ' + RegExp.index + '<br>'); </script>
Output: IE: RegExp.index == 0 FF: RegExp.index == undefined Opera: same as FF Safari: same as FF
Output: IE:
RegExp.input == Able was I ere I saw Elba. RegExp.$_ == Able was I ere I saw Elba. FF: same as IE Opera: RegExp.input == undefined RegExp.$_ == undefined Safari: same as IE
4.9 RegExp.lastIndex
JScript adds this property to the RegExp constructor even for non global regular expressions, and sets it value to the index in the string following the match, or to -1 if there is no match. The property has the attributes { DontEnum, DontDelete, ReadOnly }. Example:
<script> var s = "Able was I ere I saw Elba."; var re = /((\w+) (\w+) (\w+) (\w+) (\w+) (\w+) (\w+)(.*))/; re.exec(s); document.write('RegExp.lastIndex == ' + RegExp.lastIndex + '<br>'); </script>
Output: IE: RegExp.lastIndex == 26 FF: RegExp.lastIndex == undefined Opera: same as FF Safari: same as FF Example:
<script> var s = "Able was I ere I saw Elba."; var re = /foo/; re.exec(s); document.write('RegExp.lastIndex == ' + RegExp.lastIndex + '<br>'); </script>
Output: IE: RegExp.lastIndex == -1 FF: RegExp.lastIndex == undefined Opera: same as FF ________________________________________________________________________ Draft Page 73 of 87
Safari: same as FF
Output: IE: RegExp.lastMatch == Able was I ere I saw Elba. RegExp['$&'] == Able was I ere I saw Elba. FF: same as IE Opera: RegExp.lastMatch == undefined RegExp['$&'] == undefined Safari: same as IE
Output: IE: RegExp.lastParen == . RegExp['$+'] == . FF: same as IE Opera: RegExp.lastParen == undefined RegExp['$+'] == undefined Safari: same as IE
Output: IE: RegExp.leftContext == RegExp['$`'] == FF: same as IE Opera: RegExp.leftContext == ________________________________________________________________________ Draft Page 75 of 87
Output: IE: RegExp.rightContext == RegExp['$''] == FF: same as IE Opera: RegExp.rightContext == RegExp['$''] == undefined Safari: same as IE
var re = /((\w+) (\w+) (\w+) (\w+) (\w+) (\w+) (\w+)(.*))/; var a = re.exec(s); for (var i = 1; i < a.length; i++) { document.write('RegExp[\'$' + i + '\'] == ' + RegExp['$' + i] + '; ' + 'a[' + i + '] == ' + a[i] + '<br>'); } </script>
Output: IE: RegExp['$1'] == Able was I ere I saw Elba.; a[1] == Able was I ere I saw Elba. RegExp['$2'] == Able; a[2] == Able RegExp['$3'] == was; a[3] == was RegExp['$4'] == I; a[4] == I RegExp['$5'] == ere; a[5] == ere RegExp['$6'] == I; a[6] == I RegExp['$7'] == saw; a[7] == saw RegExp['$8'] == Elba; a[8] == Elba RegExp['$9'] == .; a[9] == . FF: same as IE Opera: same as IE Safari: same as IE
if (re.compile) { re.compile(p, f); var a = s.match(re) // Find matches. document.write(a); } else { document.write('RegExp.compile undefined'); } </script>
Output: IE: A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P FF: same as IE Opera: same as IE Safari: RegExp. compile undefined
Output: IE: 5009: 'y' is undefined FF: 0: undefined Opera:0: undefined (followed by reference errors in lines 7, 10 Safari: same as Opera but no error diagnostics seen.
Example:
<script> var err = new Error(101, "describe the error"); for (var i in err) { document.write(i + ' : ' + err[i] + '<br>'); } </script>
Output: IE: name : Error number : 101 description : describe the error message : describe the error FF: message : 101 fileName : describe the error lineNumber : 2 stack : Error("101","describe the error")@:0 @file:///D:/jsJavaScript/test.html:2 name : Error Opera: message : 101 Safari: same as Opera
4.19 ActiveXObject
The ActiveXObject represents a reference to a OLE Automation object and can be used to programmatically access applications that support an OLE Automation model. For example, Microsoft Excel supports an OLE automation model that can be programmatically accessed through COM. The ActiveXObject object provides the same access to JScript programmers. For the purpose of accessing the applications automation model, ActiveXObect creates a new instance of the application. Example:
<script> /* Invoke Excel and get a reference to its "Application" object Get a reference to the "Sheet" object (also creates a sheet) Make the application visible Quit the application */ var xlApp = new ActiveXObject("Excel.Application"); var xlSheet = new ActiveXObject("Excel.Sheet"); xlSheet.Application.Visible = true; xlSheet.Application.Quit(); </script>
Output: IE7: This brings up Excel, creates a sheet, makes the application visible, and then quits the application. FF: Syntax error (ActiveXObject undefined) Opera: same as FF Safari: no output (not supported), but no error is reported
4.20 GetObject
This is similar to ActiveXObject except that while ActiveXObect creates a new instance of the application GetObject(...) grabs an instance of the application that is already running. This is no longer supported. It was withdrawn from IE5 onwards for security reasons.
value before being passed to the VBArray constructor. This can only be done by retrieving the value from an existing ActiveX or other object. VBArrays can have multiple dimensions. The indices of each dimension can be different. The dimensions method retrieves the number of dimensions in the array; the lbound and ubound methods retrieve the range of indices used by each dimension. VBArray supports the following methods (as shown in the example code below):
dimensions() lbound(i) ubound(i) toArray() getItem(i)
Example:
<script language="VBScript"> Function CreateVBArray() Dim i, j, k Dim a(2, 2) k = 1 For i = 0 To 2 For j = 0 To 2 a(j, i) = k document.writeln(k) k = k + 1 Next document.writeln("<BR>") Next CreateVBArray = a End Function </script> <script language="Javascript"> function VBArrayTest(vbarray) { var a = new VBArray(vbarray); var d = a.dimensions(); document.write("vbarray has " +d +" dimensions"); document.write("<br>"); var i, j; for (i = 1; i <= d; i++) { document.write("dimension: " +i); document.write(" lower bound: " +a.lbound(i)); document.write(" upper bound: " +a.ubound(i)); document.write("<br>"); }
var b = a.toArray(); for (j = 0; j < 9; j++) { document.writeln(b[j]); } document.write("<br>"); for (i = 0; i <= 2; i++) { for (j =0; j <= 2; j++) { document.writeln(a.getItem(i, j)); } } } VBArrayTest(CreateVBArray()); </script>
Output: IE: 123 456 789 vbarray has 2 dimensions dimension: 1 lower bound: 0 upper bound: 2 dimension: 2 lower bound: 0 upper bound: 2 123456789 147258369 FF: syntax error (CreateVBArray() not defined) Opera: same as FF Safari: no output (not supported), but no error is reported.
Example
<script> var a = new Array(); a.push(1); a.push(2); var e = new Enumerator(a);
Output: IE: 1 2 FF: Syntax error Opera: same as FF Safari: no output (not supported), but no error is reported
5 References
ES3 spec JScript Conditional Compilation
6 Appendix
ES3 implementation loopholes: Section name Identifiers Section Text "implementations may allow additional legal identifier characters based on the category assignment from later versions of Unicode" "An implementation may extend the regular expression constructor's grammar, but it should not extend the RegularExpressionBody and RegularExpressionFlags productions or the productions used by these productions." "If the call to new RegExp generates an error, an implementation may, at its discretion, either report the error immediately while scanning the program, or it may defer the error until the regular expression literal is evaluated in the course of program execution"
"external code might be able to detect a difference between various Non-a-Number values, but such behaviour is implementation-dependent" "Whether or not a native object can have a host object as its [[Prototype]] depends on the implementation." "An implementation may also provide implementationdependent internal functions that are not described in this specification. " "Whether calling a host object can return a value of type Reference is implementation-dependent." typeof result for "host objects" is implementation dependent "The mechanics of enumerating the properties (step 5 in the first algorithm, step 6 in the second) is implementation dependent. The order of enumeration is defined by the object."
"If there is more than one object E satisfying these criteria, choose one at the implementation's discretion." ; "13. At the implementation's discretion, go to either step 2 or step 14." ; "Step 1 allows an implementation to optimise the common case of a function A that has a nested function B where B is not dependent on A. In this case the implementation is allowed to reuse the same object for B instead of creating a new one every time A is called. Step 13 makes this optimisation optional; an implementation that chooses not to implement it will go to step 2." ; plus additional verbiage about "joined" functions Native ECMAScript Objects "Unless otherwise specified in the description of a particular function, if a function or constructor described in this section is given more arguments than the function is specified to allow, the behaviour of the function or constructor is undefined. In particular, an implementation is permitted (but not required) to throw a TypeError exception in this case." The Global Object "The values of the [[Prototype]] and [[Class]] properties of the global object are implementation-dependent" parseInt (string , radix) "When radix is 0 or undefined and the string's number begins with a 0 digit not followed by an x or X, then the implementation may, at its discretion, interpret the number either as being octal or as being decimal. Implementations are encouraged to interpret numbers in this case as being decimal."
". (However, if R is 10 and Z contains more than 20 significant digits, every significant digit after the 20th may be replaced by a 0 digit, at the option of the implementation; and if R is not 2, 4, 8, 10, 16, or 32, then Result(16) may be an implementation-dependent approximation to the mathematical integer value that is represented by Z in radix-R notation.)" "4. If the value is a host object, then actions are taken and a result is returned in an implementation-dependent manner that may depend on the host object." "If the object is the result of calling the Object constructor with a host object (section 15.2.2.1), it is implementationdefined whether valueOf returns its this value or another value such as the host object originally passed to the constructor." "An implementation-dependent representation of the function is returned. This representation has the syntax of a FunctionDeclaration. Note in particular that the use and placement of white space, line terminators, and semicolons within the representation string is implementation-dependent." "a separator string that has been derived in an implementation-defined locale-specific way" "Whether the XXX function can be applied successfully to a host object is implementation-dependent."
Object.prototype. valueOf ( )
Function.prototype. toString ( )
Array.prototype. toLocaleString ( ) Array.prototype.concat Array.prototype.join Array.prototype.pop Array.prototype.push Array.prototype.reverse Array.prototype.shift Array.prototype.slice Array.prototype.sort Array.prototype.splice Array.prototype.unshift Array.prototype.sort
String.prototype. localeCompare
String.prototype.replace
"If comparefn is not undefined and is not a consistent comparison function for the elements of this array (see below), the behaviour of sort is implementation-defined. " ;"If there exist integers i and j and an object P such that all of the conditions below are satisfied then the behaviour of sort is implementation-defined:" "The two strings are compared in an implementationdefined fashion. " ; "The actual return values are left implementation-defined to permit implementers to encode additional information in the result value" $n: "If n>m, the result is implementation-defined." ; $nn: "If nn>m, the result is implementation-defined"
Number.prototype.toString
Number.prototype. toLocaleString Number.prototype.toFixed Number.prototype. toExponential Number.prototype. toPrecision Function properties of math object Daylight Saving Time Adjustment TimeClip (time)
"If radix is an integer from 2 to 36, but not 10, the result is a string, the choice of which is implementationdependent." "This function is implementation-dependent, and it is permissible, but not encouraged, for it to return the same thing as toString." "An implementation is permitted to extend the behaviour of XXX for values of fractionDigits less than 0 or greater than 20. In this case XXX would not necessarily throw RangeError for such values." "An implementation is permitted to extend the behaviour of toPrecision for values of precision less than 1 or greater than 21."
"An implementation of ECMAScript is expected to determine the daylight saving time algorithm" "The point of step 3 is that an implementation is permitted a choice of internal representations of time values, for example as a 64-bit signed integer or as a 64-bit floatingpoint value. Depending on the implementation, this internal representation may or may not distinguish -0 and +0"
Date.parse (string)
"the value produced by Date.parse is implementationdependent when given any string value that could not be produced in that implementation by the toString or toUTCString method." "When the UTC function is called with fewer than two arguments, the behaviour is implementation-dependent."
Date.UTC
Date.prototype.toString
"The contents of the string are implementation-dependent, but are intended to represent the Date in the current time zone in a convenient, human-readable form"
Date.prototype. toDateString Date.prototype. toTimeString Date.prototype. toLocaleString Date.prototype. toLocaleDateString Date.prototype. toLocaleTimeString Date.prototype. toUTCString new RegExp(pattern, flags)
"The contents of the string are implementation-dependent, but are intended to represent the XXX portion of the Date"
"The contents of the string are implementation-dependent, but are intended to represent the Date in a convenient, human-readable form in UTC." "The source property of the newly constructed object is set to an implementation-defined string value in the form of a Pattern based on P." "The initial value of Error.prototype.message is an implementation-defined string." "Returns an implementation defined string." "and in the implementation-defined message property of the prototype object." "The initial value of the message property of the prototype for a given NativeError constructor is an implementationdefined string." Various allowances for implementation dependent erorr behavior (or lack there of) related to implementation dependent extensions "Some implementations of ECMAScript have included additional properties for some of the standard native objects. This non-normative annex suggests uniform semantics for such properties without making the properties or their semantics part of this standard."
Error.prototype.message
Errors
Additional Properties
7 Revision history
9 Sep 2007 pratapL Creation