Jump to main content
Menu

Introduction to JavaScript

JavaScript History, Versioning, and Browser Support

  • Created by Brendan Eich at Netscape in 1995, JavaScript support was first implemented in the Netscape 2.0 browser.
  • Microsoft, not wanting to be outdone, introduced a competing language called JScript in the Internet Explorer 3.0 browser.
  • In an effort to standardize the language, the European Computer Manufacturers Association (ECMA) released the first version of ECMAScript in 1997; the standard is ECMA-262.
    • ECMAScript defines the Core of the language, which is the syntax, how variables work, data structures, and some core objects like Math(), Date(), Array(), etc. It describes how JavaScript works as a programming language.
    • ECMAScript does not define any Application Programming Interfaces (APIs) like the Document Object Model (DOM); the W3C standardized the DOM.
  • Our focus is primarily ECMAScript 6 (ES6). This is not the latest version of ECMAScript, but it is a version that works in all major browsers. It was also a version with major additions and enhancements (more recent versions have less extensive additions).
  • Articles on this site do use some features of later ECMAScript versions, but the foundation is ES6.
  • If you need to have workable code that includes Internet Explorer support, a transpiler is needed.
    • A transpiler is a source-to-source compiler so that, for example, ES6 code is compiled to ECMAScript 3 (ES3) code during a build process (ES3 support goes back a very, very long way).
    • Babel is a popular transpiler for ECMAScript.
    • Polyfills are added for features missing from ECMAScript 3. A polyfill is JavaScript that adds missing capabilities / feature support to a browser.
  • JavaScript is not Java. The similarity in naming was done for marketing reasons (one of JavaScript's earlier names was LiveScript), so that JavaScript could ride on the excitement generated by Java at that time. They are very different languages.

JavaScript as a Programming Language

  • Object-Oriented (OO)
    • In JavaScript everything is an object.
    • Objects have properties (data attributes for that object) and methods (actions that can be called from that object).
    • What confuses traditional OO (object-oriented) programmers is that JavaScript's OO is prototypal rather than classical. Languages such as Java, Python and Ruby use classical OO.
    • In prototypal OO when an object of a specific type is created the newly created object has all of the methods and properties from the core object of that type, as well as from any object that is a parent or grandparent in the hierarchy of core objects.
      • When a String object is created in JavaScript (e.g., let greeting = 'Hello World';) that object has all the methods and properties of the core String object, as well as the methods and properties of the core Object object (at the top of the object hierarchy).
      • It is possible to extend the core objects, which adds methods and properties to every instance of them.
    • Classical OO, in contrast, handles object definition via classes. Each class is a blueprint of the object, with its methods and properties detailed.
      • The programmer then creates an instance of that class, typically via the new keyword. The instance has all the methods and properties of the class.
      • Classes can be organized into parent / child relationships and a variety of controls can be set for what code can access a given method or property.
      • The prototypal OO of JavaScript lacks the flexibility and degree of control that classical OO affords.
    • In ECMAScript 5 (ES5) - released in December 2009 (12 years into ECMAScript development) - the language finally gained support for classical OO syntax. These classes are special types of functions that behave consistently with other classical OO languages, albeit with some limitations.
    • So JavaScript (at least in modern browsers) supports both prototypal and classical objects.
  • Interpreted / Dynamic
    • Rather than being compiled into machine code ahead of time, JavaScript is read and acted upon as the interpreter (the program for parsing JavaScript that is built into the browser or runs server-side, in the case of Node.js) reads the code.
    • Many Web programming languages are this way; PHP and Ruby are two additional examples.
    • The downside of being an interpreted language is performance (speed); the compiled languages will always be faster because the code is in an optimized format already.
    • Since commands are acted upon immediately, you need to be careful with sequencing. If you have a dependency on a piece of code (such as one JavaScript file depending on functions in another JavaScript file), the interpreter needs to have already parsed that other code.
  • Loosely Typed
    • The "type" referred to here means the type of object, such as whether a variable is a String object, a Number object, etc.
    • Strongly typed languages, such as Java and Ruby, will not alter the type of an object unless you specifically make the change via a special method. Changing the type is referred to as casting.
    • Loosely typed languages, on the other hand, allow a variable to change from one object type to another object type without any special methods.
      • In JavaScript it is common for String objects (e.g., "12") to change to Number objects (e.g., 12) and vice versa.
      • Using the == and != operators automatically converts types to see if a match can be made.
      • The primary drawbacks of loose typing are that it complicates troubleshooting and can result in unintended behavior. In strongly typed languages at least you know that the String you created is still a String later on when you are comparing its value to something else.
      • To prevent JavaScript from flipping object types as it checks for equivalence (or non-equivalance) use === and !==, as those check both object type as well as value.
  • Supports Metaprogramming
    • Your JavaScript code can be self-modifying. For example, a function can be rewritten on the fly, if necessary.
    • This is very helpful in polyfills, as a flawed browser implementation of a JavaScript method can be overwritten immediately, before it gets used.
  • Cross-Platform
    • For client-side JavaScript (running inside the browser), support is dependent on the interpreter built into the browser.
    • It is also entirely possible to write a JavaScript program that is not Web-based; as long as there is an interpreter it will work.

Core Objects in JavaScript

  • JavaScript (and ECMAScript) have a number of Core objects, which have predefined methods and properties and serve as the basis for the language.
  • These Core objects are not specific to the Web; they can be used in any environment.
  • The objects are in a hierarchy, with the generic Object at the top:
    • Object object
      • Array object
      • Boolean object
      • Date object
      • Function object
      • Map object
      • Math object
      • Number object
      • RegExp object
      • Set object
      • String object
  • Over time additional objects have been added to the JavaScript supported in browsers; we will see this when we get to XHR (for example). Those objects are not part of the Core, because they rely on specific protocols that may not exist outside of a Web environment.

Some Uses for JavaScript

  • Modifying tags, attributes, and page content in response to user actions
    • JavaScript uses an API (Application Programming Interface) referred to as the DOM (Document Object Model) to accomplish those changes.
  • Validating form data, placing and reading cookies and other data, modifying the browser window, or opening new windows
  • Computations (e.g., a mortgage calculator)
    • Uses the built-in Math() object and various mathematical operators such as addition, multiplication, etc.

The Limitations of JavaScript

Due to security and privacy concerns (to prevent malicious coders from damaging user computers or stealing personal data when the website is visited), various limitations are placed on JavaScript:

  • No permission to read from the hard disk
  • No permission to write to the hard disk
    • Cookies and the browser database are again the exception. The user may have blocked all cookies via their browser preferences or blocked just your website. Blocking access to the browser's database is more tricky for users.
  • No ability to write to <input type="file" /> fields
    • That would allow a malicious coder to write in the address of a sensitive file on your computer and then call the submit() method on the form automatically, sending that file to their server.
  • No access to HTTP POST data
    • That would be snooping on data being sent to and from the server via method="post" forms.
    • Imagine calling a JavaScript file from an advertiser's domain in order to display their banner ad. However, that company is not ethical so they want to spy on the traffic for every user that is seeing the banner ad. This prevents the POST data from being accessed.
    • GET data can be accessed via the Browser Object Model, however, since it is part of the URL.
  • No access to browser history addresses
  • Only JavaScript-opened windows can be modified
    • If your code attempts to close a window not opened by JavaScript, the user typically gets a prompt asking whether to allow this to happen.
    • Windows opened via JavaScript can be closed without this confirmation.
  • No access to web pages from a different domain or even a different subdomain at your own website
    • This is typically referred to as the same-source policy
    • Windows opened from my.learningtocode.info and your.learningtocode.info cannot communicate
    • The Browser Object Model offers a workaround to this, through specifying the domain property of the document object.
  • No access to cookies placed from another domain
    • The same-source policy is the reason, but there is a critical exception.
    • If you call a script from another server they are considered a trusted source and thus they can access cookies for your domain.
    • XSS (Cross-Site Scripting) attacks have been on the rise in recent years; JavaScript is inserted into your HTML code (through various mechanisms) and when a user visits the page their cookie data and browser database entries for your website are sent to the hacker's website.
    • The samesite setting for the cookie is one way to mitigate this issue.

Additional Browser and Network Protections

  • Most browsers prohibit opening windows smaller than 100 x 100 or windows placed outside the visible area of the browser.
  • Proxy servers and firewalls sometimes strip out JavaScript. This happens most often in corporate environments. Again, it is a security concern.

The <script></script> Tag

  • The <script></script> tag is used for embedded and external JavaScript.
  • You can only use a given <script></script> tag for either embedded or external; not both. If you accidentally use both in the same tag then only the external code will be used (it will overwrite the embedded JavaScript).
  • There is no limit to the number of <script></script> tags that can be used in a document. They can be specified in the <head></head> region as well as in the <body></body> region. The ideal location depends on the situation.
  • Please note that the <script> tag cannot be self-terminated; it must be closed normally via </script> because the code being loaded (for external scripts) needs to be within that container.
Attribute Value Purpose / Behavior Notes
async async The file will be executed as soon as it is downloaded; it will not execute in source code order. Only works with external files (not embedded JavaScript).
defer defer This attribute allows a script to download as the rest of the page is being downloaded (it does not pause other downloads). Just before the DOMContentLoaded event fires, the code in the deferred file is executed.

Relative ordering of deferred scripts is maintained, so if you have multiple script tags with defer, they execute in the order they occur in the source code.

This attribute can only be used when loading script files (it does not work with embedded scripts).

If you prefer putting script tags inside the head region of your HTML, this is a fine approach.

src src="filename.js" Loads an external .js file.

HTML rendering is halted until external .js files are downloaded, although eventually rendering continues if the .js file is not coming fast enough (the time limit varies by browser).

This issue can be avoided by calling scripts from the bottom of a page (just before </body>), placing them in the head region and specifying defer, or using the async attribute.

Ideally use only one external file, in order to reduce HTTP requests (thus speeding up rendering) and increase the chances of caching.
crossorigin
  • crossorigin="anonymous" (no credentials related to cross-domain requests are passed)
  • crossorigin="use-credentials" (pass user credentials, such as via cookies, when making the file request)
Only relevant if making cross-domain requests. Usually fine to omit.

Embedding JavaScript Example

<script>
alert('Hello World');
</script>

Calling an External JavaScript File Example

<html lang="en" dir="ltr">
<head>
  <title>External JavaScript Example</title>
  <meta charset="utf-8" />
</head>
<body>

  <script src="example.js"></script>
</body>
</html>

The <noscript></noscript> Tag

  • <noscript></noscript> content is only displayed when JavaScript is not supported by a user agent (by a browser, in this case) or when support has been disabled.
  • Content inside these tags is shown to those user agents, which would otherwise not show anything from the action of the scripting code.
  • <noscript></noscript> is either before or after <script></script>; they are not nested.
  • As an example, a slideshow dependent on JavaScript could have this:
    <noscript>
    <p>Please enable JavaScript to experience the slideshow.</p>
    </noscript>
    
  • Unfortunately, <noscript></noscript> is not very useful in practice because it only triggers in the extreme case that JavaScript is completely unavailable.
  • More commonly the device supports JavaScript to a small extent (and hopefully the support is in the area we need) or has had JavaScript selectively turned off (via browser preferences). In those situations <noscript></noscript> is of no help at all; it will not show its content.
  • Non-technical users are unlikely to know what JavaScript is, or how to enable it, so seeing the message won't necessarily help them.

Comments in JavaScript

  • JavaScript comments are preceded by // or enclosed in /* */
  • The use of // is for single-line comments and makes everything to its right (on that line) into a comment.
  • /* */ encloses multi-line comments
  • // This comment impacts the first line
    // This comment is for the second line

    /* This is a comment */

    /* This
    is also
    a comment
    */

Syntax and Other Coding Rules

Syntax is the set of rules for properly written code. Syntax violations produce unintended consequences, most commonly interpreter failure and the output of various error messages.

Unlike HTML and CSS, a parsing error in JavaScript generally derails the entire script. HTML and CSS are much more forgiving, as browsers may try to fix the HTML themselves and malformed CSS will usually just cause that particular rule and the next rule to be ignored.

Syntax can be fairly involved, so just the basics are covered here (other articles on this site provide more details).

  • Semicolons
    • It's a good practice to end statements with a semicolon.
    • That said, there are cases in ES6 where semicolons are not needed.
  • White Space
    • Extra spaces on the same line are ignored by JavaScript.
    • let x='hello'; is the same as let x = 'hello';
  • Variable and Function Naming
    • Variable and function names must start with a letter or the underscore character.
  • Case Sensitivity
    • When you define a variable or function, the capitalization used for its name must be followed when the variable is referenced later or the function is called later.
    • JavaScript requires core objects and their methods to use a specific capitalization.
  • Splitting a Text String Across Multiple Lines
    • The backslash character \ is used to safely break the text across more than one line.
    • The backlash must be inside the text string:
      alert('Hello \
      World');
      
  • Matching Opening / Closing Characters
    • Match up " with ", ' with ', ( with ), { with }, [ with ], etc.
  • Escaping Characters
    • A backslash \ can also be used to escape the next character (make the interpreter just output the character as text and not treat the character as having any special meaning). For example:
      alert("JavaScript has \"interesting\" syntax");
      

      Note: Use of single quotes or backticks in either location (around the entire string or around just the single word) would alleviate the need to escape the characters, as those would not run into issues with the double quotes.

  • Pseudo-Protocol
    • The javascript: pseudo-protocol precedes attribute values that contain JavaScript, if the attribute is not an event handler (such as onclick).
    • Values inside event handler attributes are assumed to be scripting instructions, so they are automatically passed to the JavaScript interpreter, without the need for the pseudo-protocol.
    • For example:
      <a href="javascript:window.close();">Close Window</a>
      
    • Please note that the pseudo-protocol is something you will see in old approaches and should be avoided. There is no need for it and, to make matters worse, it introduces accessibility issues (in the previous code, the link would not work if JavaScript was disabled).

Guiding Principles & Best Practices

  • Build for Reuse
    • The use of functions in JavaScript, which are passed values (known as parameters or arguments) and produce a result based on those values, supports reuse across multiple pages.
    • Placing JavaScript in external files also supports reuse.
  • Ensure Graceful Degradation
    • Make sure that the page functions acceptably and that content can still be accessed if JavaScript support is disabled or absent.
  • Design for Progressive Enhancement
    • The flip-side of graceful degradation, progressive enhancement means that your script provides more functionality to the browsers that can support it.
  • Unobtrusive Scripting
    • Related to graceful degradation, an unobtrusive approach is one that adds a usability and/or accessibility enhancement to the page and simply disappears (without detracting from the user experience) if JavaScript is disabled.
    • Unobtrusive scripting relies upon structure (HTML) and behavior (JavaScript) being as separate as possible.
  • Design for Scalability
    • Write your code so that everything still works properly if content is added or removed from the page.
  • Avoid Conflicts With Other Scripts
    • Most websites pull in JavaScript from various sources, whether it is Google Analytics, a banner ad, or one of a hundred different widgets that you use on your pages (such as a clock, a calendar, a weather report, etc.)
    • Our goal is to avoid collisions between our scripts and theirs, which most often come in the form of global variables having the same name.
  • Optimize Performance (Speed)
    • There are many ways to accomplish this, and various other articles on this site explore ways to improve performance.
    • For their part, the browser developers have been speeding up their JavaScript interpreters in an attempt to be the fastest at handling JavaScript.
  • Minimize Browser Memory Load
    • We run the risk of crippling the browser by consuming too much memory.
    • This is exacerbated by users having thirty browser tabs open.
  • Comment Your Code
    • When you return to your code after weeks or months, you will wonder what a variable or function does; comments can serve as valuable reminders.
    • Comment are also quite helpful when someone 'inherits' your code.