JavaScript basics tutorial: 33 Concepts Every JavaScript Developer Should Know

This repository was created with the intention of helping developers master their concepts in JavaScript. It is not a requirement, but a guide for future studies. It is based on an article written by Stephen Curtis.

Table of Contents

  • Call Stack
  • Primitive Types
  • Value Types and Reference Types
  • Implicit, Explicit, Nominal, Structuring and Duck Typing
  • == vs === vs typeof
  • Function Scope, Block Scope and Lexical Scope
  • Expression vs Statement
  • IIFE, Modules and Namespaces
  • Message Queue and Event Loop
  • setTimeout, setInte...

Raising JavaScript errors in Ruby E2E tests (RSpec, Cucumber)

A JavaScript error in an E2E test with Selenium will not cause your test to fail. This may cause you to miss errors in your frontend code.

Using the BrowserConsole helper below you can check your browser's error console from your E2E tests.

The following will raise BrowserConsole::ErrorsPresent if there is an error on the browser console:

BrowserConsole.assert_no_errors!

Ignoring errors

You can ignore errors by their exact message:

BrowserConsole.ignore('Browser is burning')

You can ignore errors with me...

JavaScript: Testing the type of a value

Checking if a JavaScript value is of a given type can be very confusing:

  • There are two operators typeof and instanceof which work very differently.
  • JavaScript has some primitive types, like string literals, that are not objects (as opposed to Ruby, where every value is an object).
  • Some values are sometimes a primitive value (e.g. "foo") and sometimes an object (new String("foo")) and each form requires different checks
  • There are three different types for null (null, undefined and NaN) and each has different rules for...

Capybara: Execute asynchronous JavaScript

Capybara provides execute_script and evaluate_script to execute JavaScript code in a Selenium-controlled browser. This however is not a good solution for asynchronous JavaScript.

Enter evaluate_async_script, which allows you to execute some asynchronous code and wait until it finishes. There is a timeout of a couple of seconds, so it will not wait forever.

Use it like this:

page.evaluate_async_script(<<~JS)
  let [done] = arguments
  doSomethingAsynchronous().then(() => {
    done() // call this to indicate we're done
  })
J...

Minifying object properties in JavaScript files

An introduction to mangling

When you minify ("compress", "optimize") your JavaScript for production, the names of your functions and variables will be renamed for brevity. This process is often called mangling.

E.g. if this is your source code:

function function1() {
  function2()
}

After mangling it would look like this:

function a() {
  b()
}

Object properties are not mangled by default

Minfiers never mangle properties by default, as this can be an unsafe transformation. This leads to larger file sizes if...

How to evaluate CSS media queries in JavaScript

To make CSS rules dependent on the screen size, we use media queries:

@media (max-width: 500px) {
  // rules for screen widths of 500px or smaller
}

Browsers will automatically enable and disable the conditional rules as the screen width changes.

To detect responsive breakpoints from JavaScript, you may use the global matchMedia() function. It is supported in all brow...

Accessing JavaScript objects from Capybara/Selenium

When testing JavaScript functionality in Selenium (E2E), you may need to access a class or function inside of a evaluate_script block in one of your steps. Capybara may only access definitions that are attached to the browser (over the window object that acts as the base). That means that once you are exporting your definition(s) in Webpacker, these won't be available in your tests (and neither in the dev console). The following principles/concepts also apply to Sprockets.

Say we have a StreetMap class:

// street_map.js
class S...

Generating test images on the fly via JavaScript or Ruby

When you need test images, instead of using services like lorempixel or placehold.it you may generate test images yourself.

Here we build a simple SVG image and wrap it into a data: URI. All browsers support SVG, and you can easily adjust it yourself.
Simply set it as an image's src attribute.

JavaScript

Simple solution in modern JavaScript, e.g. for use in the client's browser:

function svgUri(text) {
  let svg = `
    <svg wid...

How to create giant memory leaks in AngularJS (and other client-side JavaScript)

This guide shows how to create an AngularJS application that consumes more and more memory until, eventually, the browser process crashes on your users.

Although this guide has been written for Angular 1 originally, most of the advice is relevant for all client-side JavaScript code.

How to observe memory consumption

To inspect the amount of memory consumed by your Javascripts in Chrome:

  • Open an incognito window
  • Open the page you want to inspect
  • Press Shift + ESC to see a list of Chrome processes...

Heads up: JavaScript does not like big numbers

In a JavaScript console, type this:

> 9112347935156469760
9112347935156470000

Ooops. And that's not a float!

This occurs because JavaScript uses double precision floats to store numbers.

So according to IEEE floating point definition only numbers between -(2^53 - 1) (-9007199254740991) and 2^53 - 1 (9007199254740991) can safely be represented in JavaScript.

Note that ECMAScript 6 will probably also offer [Number.MAX_SAFE_INTEGER](https://developer.mozilla.org/en-US/docs/W...

JavaScript: Comparing objects or arrays for equality (not reference)

JavaScript has no built-in functions to compare two objects or arrays for equality of their contained values.

If your project uses Lodash or Underscore.js, you can use _.isEqual():

_.isEqual([1, 2], [2, 3]) // => false
_.isEqual([1, 2], [1, 2]) // => true

If your project already uses Unpoly you may also use up.util.isEqual() in the same way:

up.util.isEqual([1, 2], [2, 3]) // => false
up.util.isEqual([1, 2], [1, 2]) // => true

If you are wri...

You should probably load your JavaScript with <script defer>

It is generally discouraged to load your JavaScript by a <script src> tag in the <head>:

<head>
  <script src="app.js"></script>
</head>

The reason is that a <script src> tag will pause the DOM parser until the script has loaded and executed. This will delay the browser's first contentful paint.

A much better default is to load your scripts with a <script src defer> tag:

<head>
  <script src="app.js" defer></script>
</head>

A deferred script has many useful properties:

  • I...

The JavaScript Object Model: Prototypes and properties

Speaker today is Henning Koch, Head of Development at makandra.

This talk will be in German with English slides.

Introduction

As web developers we work with JavaScript every day, even when our backend code uses another language. While we've become quite adept with JavaScript at a basic level, I think many of us lack a deep understanding of the JavaScript object model and its capabilities.

Some of the questions we will answer in this talk:

  • How does the new keyword construct an object?
  • What is the differen...

Async control flow in JavaScript: Promises, Microtasks, async/await

Slides for Henning's talk on Sep 21st 2017.


Understanding sync vs. async control flow

Talking to synchronous (or "blocking") API

print('script start')
html = get('/foo')
print(html)
print('script end')

Script outputs 'script start', (long delay), '<html>...</html>', 'script end'.

Talking to asynchronous (or "evented") API

print('script start')
get('foo', done: function(html) {
  print(html)
})
print('script end')

Script outputs 'script start', 'script end', (long ...

JavaScript without jQuery

This is a presentation from 2019-01-21.

Summary

  • We want to move away from jQuery in future projects
  • Motivations are performance, bundle size and general trends for the web platform.
  • The native DOM API is much nicer than it used to be, and we can polyfill the missing pieces
  • Unpoly 0.60.0 works with or without jQuery

Is jQuery slow?

From: Sven
To: unpoly@googlegroups.com
Subject: performance on smartphones and tablets

Hello

I just used your framework in one project and must say,
I am really pleased with it -- but o...

Cancelling event propagation

Within an event handler, there are multiple methods to cancel event propagation, each with different semantics.

  • event.preventDefault()

    Only prevents the default browser behavior for the click, i.e. going to a different url or submitting a form.

    When invoked on a touchstart event, this also prevents mouse events like click to be triggered.

  • event.stopPropagation()

    Prevents the event from bubbling up the DOM.

  • `event.st...

JavaScript: Sharing content with the native share dialog

Mobile Chrome and Safari support the "web share API" which allow you to use the native share functionality of an Android or iOS phone. Some desktop OSs like Windows or MacOS also support native share dialogs. See Can I Use for a detailed support matrix.

When clicking a share button using this API, the browser will automatically show all installed applications that support content sharing, such as Whatsapp, Facebook, Twitter, e-mail etc.

The API is extremely simple to use:

if ...

Unpoly: Loading large libraries on-demand

When your JavaScript bundle is so massive that you cannot load it all up front, I would recommend to load large libraries from the compilers that need it.

Compilers are also a good place to track whether the library has been loaded before. Note that including same <script> tag more than once will cause the browser to fetch and execute the script more than once. This can lead to memory leaks or cause duplicate event handlers being registered.

In our work we mostly load all JavaScript up front, since our bundles are small enough. We recent...

Webpack(er): Analyze the size of your JavaScript components

We're always striving towards keeping our website's JavaScript as small as possible.

If you're using webpack(er), you can use the webpack-bundle-analyzer plugin to get a good overview, which of your JavaScript modules take up how much space, and where you can optimize.

To use it, add it via npm or yarn

yarn add webpack-bundle-analyzer

Then add this to your environment.js:

// Uncomment this code to show statistics of bundle sizes. Generated file will automatically...

Unobtrusive JavaScript helper to progressively enhance HTML

The attached compiler() function below applies JavaScript behavior to matching HTML elements as they enter the DOM.

This works like an Unpoly compiler for apps that don't use Unpoly, Custom Elements or any other mechanism that pairs JavaScript with HTML elements.

The compiler() function is also a lightweight replacement for our legacy [$.unobtrusive()](https://makandracards.com/makandra/4-unobtrusiv...

JavaScript: Humanizing durations

Modern JavaScript includes Intl.NumberFormat to format numbers in different formats and locales.
In this card, we describe a wrapper for it that humanizes a given number of seconds in the "next best" unit, like seconds, minutes, etc.

Example usage

>> new Duration(42).humanized()
=> '42 Sekunden'
>> new Duration(123456).humanized()
=> '1 Tag'
>> new Duration(123456).humanized('es')
=> '1 día'

Code

Here is the code ...

Detect the current Rails environment from JavaScript or CSS

Detecting if a Javascript is running under Selenium WebDriver is super-painful. It's much easier to detect the current Rails environment instead.

You might be better of checking against the name of the current Rails environment. To do this, store the environment name in a data-environment of your <html>. E.g., in your application layout:

<html data-environment=<%= Rails.env %>>

Now you can say in a pi...

Exchange messages between Javascript and Flash

Flash movies (.swf files) can talk with Javascript code embedded in the same HTML page. There are two ways to do this:

  • The preferred way is to use the ExternalInterface class to call Javascript functions from ActionScript, and to bind ActionScript functions to the Flash movie's DOM element so they can be called from Javascript.
  • The deprecated way is to use the global [fscommand](http://help.adobe....

Triggering JavaScript when an element is clicked

Often people need links which are not linked directly, but should trigger execution of JavaScript.

❌ Bad workarounds

You can find a lot of workarounds for that:

  • <a href="#">Do something with js!</a>
    This defines an empty anchor. This may lead the browser to let the page jump to the top when the link is clicked, unless you call preventDefault on the event. This is probably not what you want.

  • <a href="#!">Do something with js!</a>
    This tells the browser to jump to an anchor !. It depends on the browser implementation wha...