0

The book JavaScript for PHP Developers contains the following commented code (to which I've added alert()s to display the values of single-variable-expression statements of the form

variable;

and to which I have also added the 'use strict' directive to see if that was what was causing the problem. I cannot reproduce the code on JSFiddle with Firefox. I've added my own comments to the code in large caps:

'use strict';

// Create a global variable
var john = "Jo";
alert(john);        // "Jo"
alert(window.john); // "Jo", works as a property too
                    /* BUT I GET UNDEFINED HERE */
// Create a property of the global object
window.jane = "JJ";
alert(jane);        // "JJ", works as a variable too
alert(window.jane); // "JJ"

// Delete them
alert(delete window.john); // false
                           /* BUT I GET true HERE */
alert(delete window.jane); // true

alert(john); // "Jo"
alert(jane); // undefined
             /* BUT PROGRAM CRASHES HERE */
alert(this === window); // true

In fact in the following small program the last alert function call is never reached:

window.jane = "JJ";
delete window.jane;
alert(jane); // Program Crashes
alert('Got Here');

I've tested all cases one more time here which illustrates all cases.

var a = 'John';
window.b = 'Jane';
c = 'Jack';

alert(a); // John
alert(b); // Jane
alert(c); // Jack

alert(window.a); // undefined
alert(window.b); // Jane
alert(window.c); // Jack

alert(delete a); // false
alert(delete b); // true
alert(delete c); // true

alert(a); // John
//alert(b); // would crash
//alert(c); // would crash

window.b = 'Jane';
c = 'Jack';

alert(delete window.a); // true
alert(delete window.b); // true
alert(delete window.c); // true

alert(window.a); // undefined
alert(window.b); // undefined
alert(window.c); // undefined

alert(a); // John
//alert(b); // would crash
//alert(c); // would crash

What I want to know is, is this behavior consistent across all browsers or are differences between one browser and another. Is the code from the book a mistake or was it simply run against a different browser than my own (Firefox 33.0.1)?

If someone could explain the various cases, perhaps pointing to the relevant sections of the ECMA specification, it would be greatly appreciated.

Thanks.


OK, the results I am seeing are such because I have run the code in JSFiddle inside the onload function and not at the global scope, as pointed out. Here is the result of running the comprehensive test inside a web page served from my local machine. The results on JSFiddle with the script inside the body html element are the same:

<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<script type="text/javascript">
var a = 'John';
window.b = 'Jane';
c = 'Jack';

alert(a); // John
alert(b); // Jane
alert(c); // Jack

alert(window.a); // John
alert(window.b); // Jane
alert(window.c); // Jack

alert(delete a); // false
alert(delete b); // true
alert(delete c); // true

alert(a); // John
try { alert(b); } catch (e) { alert(e); } // throws ReferenceError: b is not defined
try { alert(c); } catch (e) { alert(e); } // throws ReferenceError: c is not defined

window.b = 'Jane';
c = 'Jack';

alert(delete window.a); // false
alert(delete window.b); // true
alert(delete window.c); // true

alert(window.a); // John
alert(window.b); // undefined
alert(window.c); // undefined

alert(a); // John
try { alert(b); } catch (e) { alert(e); } // throws ReferenceError: b is not defined
try { alert(c); } catch (e) { alert(e); } // throws ReferenceError: c is not defined
</script>
</body>
</html>

and here is what happens when the ECMAScript5 'use strict' directive is also used. While I'm aware that declaring a variable without var in strict mode causes a reference error I'm not sure I can make sense of the rest of the output, in particular why does script execution terminate at certain places:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script type="text/javascript">
'use strict';

var a = 'John';
window.b = 'Jane';
try { c = 'Jack'; } catch (e) { alert(e); } // throws ReferenceError: assignment to undeclared variable c

alert(a); // John
alert(b); // Jane
try { alert(c); } catch (e) { alert(e); } // throws ReferenceError: c is not defined

alert(window.a); // John
alert(window.b); // Jane
alert(window.c); // undefined

try {
// Uncommenting any of these three following statements will cause the script to be exited
// during the parsing time; no statement from this script will be executed.
//alert(delete a);  causes script to end during parsing at runtime even though try catch block present
//alert(delete b);  causes script to end during parsing at runtime even though try catch block present
//alert(delete c);  causes script to end during parsing at runtime even though try catch block present
} catch (e) { alert(e); }

alert(a); // John
try { alert(b); } catch (e) { alert(e); } // Jane
try { alert(c); } catch (e) { alert(e); } // throws ReferenceError: c is not defined

window.b = 'Jane';
c = 'Jack';

try {
//alert(delete window.a); // causes script to end during execution at runtime even though try catch block present
//alert(delete window.b); // causes script to end during execution at runtime even though try catch block present
//alert(delete window.c); // causes script to end during execution at runtime even though try catch block present
} catch (e) { alert(e); }

/* Script stops execution at this point. Why?????

alert(window.a); // 
alert(window.b); // 
alert(window.c); // 

alert(a); // 
try { alert(b); } catch (e) { alert(e); } // 
try { alert(c); } catch (e) { alert(e); } // 
</script>
</body>
</html>

If anyone can help me interpreting why the script executions terminate in some places the way they do with strict mode it would be greatly appreciated.

Thanks.


With regards to the origninal code from the book, when run properly from within a script tag in the head of the document, I get the following output, were we can see that a ReferenceError instance due to accessing variable jane is thrown. Here is the JSFiddle for the code:

//'use strict'

// Create a global variable
var john = "Jo";
alert(john);        // "Jo"
alert(window.john); // "Jo", works as a property too

// Create a property of the global object
window.jane = "JJ";
alert(jane);        // "JJ", works as a variable too
alert(window.jane); // "JJ"

// Delete them
try { alert(delete window.john); } catch (e) { alert(e); }
// false
/* if strict mode were enforced would actually cause
   the following fatal error:
   TypeError:
   property "john" is non-configurable and can't be deleted   
*/
try { alert(delete window.jane); } catch (e) { alert(e); }
// true

alert(john); // "Jo"
try { alert(jane); } catch (e) { alert(e); } // undefined in book
/* but actually gives a:
   ReferenceError: jane is not defined
   which is a fatal error causing the script to exit
   if not caught*/
alert(this === window); // true
John Sonderson
  • 3,238
  • 6
  • 31
  • 45
  • 3
    I suspect this only happens on JSFiddle, right? If so, that's because JSFiddle wraps your JS code in an `onload` function. – Qantas 94 Heavy Oct 31 '14 at 12:46
  • 1
    Please read through these docs carefully: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var and here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode – istos Oct 31 '14 at 12:56
  • Thank you @istos for the references. There is one thing I didn't get though. With regards to the first link, what is the difference between a configurable property and a non-configurable property. Thanks. – John Sonderson Oct 31 '14 at 14:49
  • This post ( http://stackoverflow.com/questions/4862193/javascript-global-variables ) confirms that global variables declared with var cannot be deleted whereas implied globals (those created in the global scope by assignment to a variable without var) as well as globals set as properties of the global object (called window in web browsers), can be deleted. Accessing a property on an object (such as window or any other object) which does not exist either because it has never existed or because it has been deleted yields the value undefined. – John Sonderson Oct 31 '14 at 17:46
  • When a property is defined with "var a = 'John';" in the global scope, or with "a = 'John';" and ends up in the global scope, or with "window.a = 'John';", in all three cases the variable can be accessed as both a (as long as it is not hidden by an inner declaration of another variable a), or as window.a (as long as the window global object is not hidden behind another window object like here: http://jsfiddle.net/33kpgwk8/2/ ). – John Sonderson Oct 31 '14 at 17:54
  • When the global object a does not exist, accessing it as a yields a reference error and accessing it as window.a yields undefined. This completes my analysis of how JavaScript deals with global variables when ECMAScript5 strict mode is not enforced through the "'use strict';" directive, as my code snippet demonstrates. – John Sonderson Oct 31 '14 at 17:59
  • This leaves the question about which statements in strict mode cause fatal errors during runtime parse time and during runtime interpretation time without throwing exceptions. – John Sonderson Oct 31 '14 at 18:08

1 Answers1

1

Look at this part of the interface to jsfiddle:

jsfiddle screenshot

That "onLoad" selector means that the code you type into the JavaScript quadrant of the interface will be wrapped in a function for you, and that that function will serve as the "load" event handler for the window. Because your code is in a function, variables you declare at what appears to be the global level really aren't global; they're local variables in the function.

To make your code truly global, change that selection to one of the "no wrap" settings.

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • Thank you @Pointy for your reply. I've updated my post accordingly. – John Sonderson Oct 31 '14 at 14:50
  • Yes, at least the "var a;" statement was declaring a local variable (a variable with function scope) instead of a global variable. – John Sonderson Oct 31 '14 at 18:29
  • @JohnSonderson as to your other question, all parse-time errors happen (independent of how strict mode works) fail before any part of the script executes. That's why they can't be caught with `try/catch` wrappers. In particular, `alert(delete a)` is a syntax error in strict mode because the direct reference to a variable name in the `delete` expression is recognized at parse time, not runtime. – Pointy Oct 31 '14 at 18:35
  • Despite me placing the code inside a function rather than in the global scope there is still one error in the book's code though. The last statement "jane;" does not yield undefined but causes a reference error which if not caught causes the script to terminate at runtime. – John Sonderson Oct 31 '14 at 18:39
  • 1
    What statement are you talking about? I don't see a line of code like `jane;` anywhere. However, if that statement were evaluated in strict mode and no variable named "jane" were defined, that'd be a runtime exception. – Pointy Oct 31 '14 at 18:42
  • I've updated the code in my post with one more code snippet at the bottom. @Pointy The last reference to `jane` in the code from the book (which I have written as `alert(jane)` to display the value of variable `jane`) causes a `ReferenceError` instance to be thrown, and this is both in strict mode as well as non-strict mode. At least this is the case in my browser Firefox 33.0.2. Accessing `window.jane` (using the property syntax) rather than as `jane`, on the other hand, yields undefined, which is what the book probably meant to write. – John Sonderson Oct 31 '14 at 21:18
  • 1
    @JohnSonderson ok yes that makes sense. A reference to an undefined variable is an exception in any case. A reference to an undefined object property, however, is not (and should not be). – Pointy Oct 31 '14 at 21:20
  • Thank you @Pointy for your replies and all your help. There is still though an unanswered part to my post. The [JSFiddle code I posted](http://jsfiddle.net/ky56r21t/) which is run in strict mode causes the JSFiddle JSHint lint program to complain asking me to place `'use strict'` inside a function, but I need the code to be at the global scope to test out the stuff. If I save the code to a local file and run the code in a web browser the code still exits prematurely without throwing an error. Any ideas what the problem with it may be? Thanks. – John Sonderson Oct 31 '14 at 21:48
  • I've read the [following post](http://www.yuiblog.com/blog/2010/12/14/strict-mode-is-coming-to-town/) to see if I could find an answer but no luck. – John Sonderson Oct 31 '14 at 21:50
  • 1
    By default, JSHint flags global "use strict" directives because that can cause 3rd-party widgets to break. If you don't like that, you can enable the "globalstrict" option. – Pointy Oct 31 '14 at 21:56
  • Thanks @Pointy. I've found the documentation for `globalstrict` on the [JSHint online docs](http://www.jshint.com/docs/options/#globalstrict) but can't find the place in JSFiddle to enable it. Thanks. – John Sonderson Oct 31 '14 at 22:21