<script>s

Most browser-viewed websites/applications have more than one file that contains their code, and it’s common to have a few or several <script src=..></script> elements in the page that load these files separately, and even a few inline-code <script> .. </script> elements as well.

But do these separate files/code snippets constitute separate programs or are they collectively one JS program?

The (perhaps surprising) reality is they act more like independent JS programs in most, but not all, respects.

The one thing they share is the single global object (window in the browser), which means multiple files can append their code to that shared namespace and they can all interact.

So, if one script element defines a global function foo(), when a second script later runs, it can access and call foo() just as if it had defined the function itself.

But global variable scope hoisting (see the Scope & Closures title of this series) does not occur across these boundaries, so the following code would not work (because foo()‘s declaration isn’t yet declared), regardless of if they are (as shown) inline <script> .. </script> elements or externally loaded <script src=..></script> files:

  1. <script>foo();</script>
  2. <script>
  3. function foo() { .. }
  4. </script>

But either of these would work instead:

  1. <script>
  2. foo();
  3. function foo() { .. }
  4. </script>

Or:

  1. <script>
  2. function foo() { .. }
  3. </script>
  4. <script>foo();</script>

Also, if an error occurs in a script element (inline or external), as a separate standalone JS program it will fail and stop, but any subsequent scripts will run (still with the shared global) unimpeded.

You can create script elements dynamically from your code, and inject them into the DOM of the page, and the code in them will behave basically as if loaded normally in a separate file:

  1. var greeting = "Hello World";
  2. var el = document.createElement( "script" );
  3. el.text = "function foo(){ alert( greeting );\
  4. } setTimeout( foo, 1000 );";
  5. document.body.appendChild( el );

Note: Of course, if you tried the above snippet but set el.src to some file URL instead of setting el.text to the code contents, you’d be dynamically creating an externally loaded <script src=..></script> element.

One difference between code in an inline code block and that same code in an external file is that in the inline code block, the sequence of characters </script> cannot appear together, as (regardless of where it appears) it would be interpreted as the end of the code block. So, beware of code like:

  1. <script>
  2. var code = "<script>alert( 'Hello World' )</script>";
  3. </script>

It looks harmless, but the </script> appearing inside the string literal will terminate the script block abnormally, causing an error. The most common workaround is:

  1. "</sc" + "ript>";

Also, beware that code inside an external file will be interpreted in the character set (UTF-8, ISO-8859-8, etc.) the file is served with (or the default), but that same code in an inline script element in your HTML page will be interpreted by the character set of the page (or its default).

Warning: The charset attribute will not work on inline script elements.

Another deprecated practice with inline script elements is including HTML-style or X(HT)ML-style comments around inline code, like:

  1. <script>
  2. <!--
  3. alert( "Hello" );
  4. //-->
  5. </script>
  6. <script>
  7. <!--//--><![CDATA[//><!--
  8. alert( "World" );
  9. //--><!]]>
  10. </script>

Both of these are totally unnecessary now, so if you’re still doing that, stop it!

Note: Both <!-- and --> (HTML-style comments) are actually specified as valid single-line comment delimiters (var x = 2; <!-- valid comment and --> another valid line comment) in JavaScript (see the “Web ECMAScript” section earlier), purely because of this old technique. But never use them.