Skip to main content

JavaScript

JavaScript (aka ECMAScript aka ES)​

Versions, Revisions​

  • ES6 = ECMAScript 6 = ECMAScript 2015
    • arrow functions

Crash Course​

see YouTube (Code)

Terminology​

  • JavaScript runtime refers to where your javascript code is executed when you run it. That said, javascript can be executed on google chrome, in which case your javascript runtime is v8, if on mozilla - it is spidermonkey, if IE - then its chakra and if on node, again its v8. (stackoverflow comment under answer)
  • I/O: In practice, the web browser or other runtime system provides JavaScript APIs for I/O.

Implementations​

  • Google V8
    • see this discussion on stackoverflow
    • see Terminology → "JavaScript runtime"
    • from Wikipedia:
      • developed by the Chromium Project for Google Chrome and Chromium web browsers
      • V8 compiles ECMAScript directly to native machine code using just-in-time compilation before executing it
        • JIT compilation aka dynamic compilation ( source )
          • a method for improving the performance of interpreted programs
          • During execution the program may be compiled into native code to improve its performance.
          • Advantages:
            • Dynamic compilation has some advantages over static compilation.
            • When running Java or C# applications, the runtime environment can profile the application while it is being run.
            • This allows for more optimized code to be generated.
            • If the behavior of the application changes while it is running, the runtime environment can recompile the code.
      • The compiled code is additionally optimized (and re-optimized) dynamically at runtime, based on heuristics of the code's execution profile.
      • Optimization techniques used include
        • inlining
        • elision of expensive runtime properties
        • inline caching.
      • used in
        • Chromium-based web browsers
        • Firefox - parts of V8 ported to the browser for regular expressions parsing
        • many more apps (see Wikipedia)

Repl (JavaScript on the Command Line)​

Useful: Use <tab><tab> to autocomplete commands.

$ node
Welcome to Node.js v19.6.0.
Type ".help" for more information.
>

Formatting, Syntax Highlighting​

  • Install javascript syntax highlighting using nvim-treesitter.
  • Install javascript formatting using coc-prettier.

CDNs​

CDN: A content delivery network, or content distribution network.

Common CDNs​

List

Press ctrl + shift + E and roload the page in Firefox to see the used CDNs (in column "Domain").

CDNs (by popularity):

  • Google Hosted Libraries
  • cdnjs
    • e.g. cdnjs.cloudflare.com
  • jsDelivr
    • e.g. cdn.jsdelivr.net
    • official CDN of Bootstrap

Syntax​

Types​

Strings​

UTF-8​

From Wikipedia:

  • the dominant encoding for the World Wide Web (and internet technologies)
  • accounting for 97.9% of all web pages
UTF-16​

From Wikipedia:

  • for security reasons browser applications should not use UTF-16
  • UTF-16 is used by systems such as
    • the Microsoft Windows API,
    • the Java programming language and
    • JavaScript/ECMAScript.

Print​

JavaScript can "display" data in different ways: w3schools

  • Writing into an HTML element, using innerHTML.
  • Writing into the HTML output using document.write().
  • Writing into an alert box, using window.alert().
  • Writing into the browser console, using console.log().

.constructor property and .constructor.name stackoverflow

  • Check this bindings, etc

Variables​

let​

  • only use this, if you know the variable will change, otherwise use const
    • makes the code more robust

const​

mdn

  • creates block-scoped constants
  • The value of a constant
    • can't be changed through reassignment (i.e. by using the assignment operator =), and
    • it can't be redeclared (i.e. through a variable declaration).
  • However, if a constant is an object or array its properties or items can be updated or removed.

Types​

Check types via typeof operator

typeof Math.LN2 === "number";
typeof declaredButUndefinedVariable === "undefined";
typeof undeclaredVariable === "undefined";
typeof { a: 1 } === "object";

For objects use the .constructor property and .constructor.name stackoverflow

Numbers​

Number.prototype.toLocaleString​

const currencyOptions = {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}

total.toLocaleString(undefined, currencyOptions)
  • Convert total from a number to a string with two decimal places.
  • this will also convert the number to a string according to the numerical conventions that match the browser's locale
  • Use undefined as the first argument to toLocaleString to use the system locale rather than specifying a locale

Arrays​

Spread​

digitalocean

I.e. ... notation, e.g.

const cart = [...state.cart];

Use cases:

  • instead of const concatArray = array1.concat(array2) use const concatArray = [...array1, ...array2]
    • both methods do not change the existing arrays, but instead return a new array
  • instead of const pushedArray = array1.push(array2[0]) (modifies array1) use const pushedArray = [...array1, array2] (does not modify array1)
  • shallow copying
    • i.e. creating a new array from the existing one and adding a new item to the end without changing the existing one

In JavaScript, when you create an object or array and assign it to another variable, you are not actually creating a new object - you are passing a reference.

  • Shallow Copy: spread allows to make a shallow copy of an array or object without changing the existing one
    • i.e. any top level properties will be cloned, but nested objects will still be passed by reference

Array.prototype.slice​

stackoverflow

Get the last element:

var my_array = /* some array here */;
var last_element = my_array[my_array.length - 1];
  • Do not use my_array.slice(-1)[0], it is too slow.

Array.prototype.splice​

mdn

return: An array containing the deleted elements.

The splice() method changes the contents of an array by removing or replacing existing elements and/or adding new elements in place (i.e. splice() modifies the original array).

  • To access part of an array without modifying it, see slice().
  • a mutating method: It may change the content of this.
  • Although strings are also array-like, this method is not suitable to be applied on them, as strings are immutable.
  • Negative index counts back from the end of the array.
some_array.splice(start)   # remove all elements after index "start"
some_array.splice(start, deleteCount) # remove "deleteCount" elements after index "start" and keep the rest
some_array.splice(start, deleteCount, item1)
some_array.splice(start, deleteCount, item1, item2, itemN)

Array.prototype.reduce​

mdn

The reduce() method executes a user-supplied "reducer" callback function on each element of the array, in order, passing in the return value from the calculation on the preceding element. The final result of running the reducer across all elements of the array is a single value.

Initial value: The first time that the callback is run there is no "return value of the previous calculation". If supplied, an initial value may be used in its place. Otherwise the array element at index 0 is used as the initial value and iteration starts from the next element (index 1 instead of index 0).

Example:

const array1 = [1, 2, 3, 4];

// 0 + 1 + 2 + 3 + 4
const initialValue = 0;
const sumWithInitial = array1.reduce(
(accumulator, currentValue) => accumulator + currentValue,
initialValue
);

console.log(sumWithInitial);
// Expected output: 10

Array.prototype.indexOf​

array1.indexOf(x)
  • index of the first instance of x in an array1
  • return -1 if x is not present

Lists​

In JavaScript:

const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((number) => number * 2);
console.log(doubled);

Functions​

Define Functions​

Ways to Define Functions:

  • function declaration mdn
  • function expressions mdn
  • method definition mdn
    • a shorter syntax for defining a function property in an object initializer. It can also be used in classes.
    • examples

Anonymous Functions​

From javascripttutorial.net:

An anonymous function is a function without a name.

(function () {
//...
});

An anonymous function is not accessible after its initial creation. Therefore, you often need to assign it to a variable:

let show = function () {
console.log('Anonymous function');
};

show();

In this example, the anonymous function has no name between the function keyword and parentheses ().

In practice, you often pass anonymous functions as arguments to other functions. For example:

setTimeout(function() {
console.log('Execute later after 1 second')
}, 1000);
Arrow Function Notation​

ES6 introduced arrow function expressions that provide a shorthand for declaring anonymous functions.

let show = () => console.log('Anonymous function');

From w3schools: If you have only one parameter (here: val), you can skip the parentheses as well:

hello = (val) => "Hello " + val;
// instead, you can use
hello = val => "Hello " + val;
Anonymous Functions as arguments​

In practice, you often pass anonymous functions as arguments to other functions:

setTimeout(function() {
console.log('Execute later after 1 second')
}, 1000);

this​

  • In JavaScript, context refers to an object., blog.kevinchisholm.com
  • Within an object, the keyword this refers to that object (i.e. self), and provides an interface to the properties and methods that are members of that object., blog.kevinchisholm.com
  • When a function is executed, the keyword this refers to the object that the function is executed in., blog.kevinchisholm.com
  • in an arrow function: You cannot rebind this in an arrow function. It will always be defined as the context in which it was defined. If you require this to be meaningful you should use a normal function. stackoverflow

w3schools (scroll down to section "What About this?")

  • In regular functions the this keyword represented the object that called the function, which could be the window, the document, a button or whatever.
  • With arrow functions the this keyword always represents the object that defined the arrow function.

blog.kevinchisholm.com:

  • When a function executes in the global context, this refers to the global, or window object
  • When a function is a method of an Object, this refers to that object (unless it is manually executed in the context of a different object)
  • When a function executes inside of another function (no matter how deeply nested), this refers to the object whose context within which it is executed
  • When you instantiate a constructor function, inside of the instance object, this refers to the instance object

this In a DOM Event Handler​

from: digitalocean

In the browser, there is a special this context for event handlers. In an event handler called by addEventListener, this will refer to event.currentTarget. More often than not, developers will simply use event.target or event.currentTarget as needed to access elements in the DOM, but since the this reference changes in this context, it is important to know.

In the following example, we’ll create a button, add text to it, and append it to the DOM. When we log the value of this within the event handler, it will print the target.

const button = document.createElement('button')
button.textContent = 'Click me'
document.body.append(button)

button.addEventListener('click', function(event) {
console.log(this)
})
Output
<button>Click me</button>

Once you paste this into your browser, you will see a button appended to the page that says “Click me”. If you click the button, you will see <button>Click me</button> appear in your console, as clicking the button logs the element, which is the button itself. Therefore, as you can see, this refers to the targeted element, which is the element we added an event listener to.

this In Arrow Functions​

Arrow functions do not have their own this binding. Instead, they go up to the next level of execution.

const whoAmI = {
name: 'Leslie Knope',
regularFunction: function() {
console.log(this.name)
},
arrowFunction: () => {
console.log(this.name)
},
}

whoAmI.regularFunction() // "Leslie Knope"
whoAmI.arrowFunction() // undefined

It can be useful to use the arrow function in cases where you really want this to refer to the outer context. For example, if you had an event listener inside of a class, you would probably want this to refer to some value in the class.

In this example, you’ll create and append button to the DOM like before, but the class will have an event listener that will change the text value of the button when clicked.

const button = document.createElement('button')
button.textContent = 'Click me'
document.body.append(button)

class Display {
constructor() {
this.buttonText = 'New text'

button.addEventListener('click', event => {
event.target.textContent = this.buttonText
})
}
}

new Display()

If you click the button, the text content will change to the value of buttonText. If you hadn’t used an arrow function here, this would be equal to event.currentTarget, and you wouldn’t be able to use it to access a value within the class without explicitly binding it. This tactic is often used on class methods in frameworks like React.

Examples​

Try these examples!!!

  • Example 3: with normal function
    • shows that for a regular function this will represent different objects depending on how the function was called
  • Example 4: with arrow function
    • shows that for an arrow function it does not matter who is the caller, this will always be the the object that owns the function, no matter who calls the function
Example 3: 'this' in a regular function
<button id="btn">Click Me!</button>

<p id="demo"></p>

<script>
let hello = "";

hello = function() {
document.getElementById("demo").innerHTML += this;
}

//The window object calls the function:
window.addEventListener("load", hello);

//A button object calls the function:
document.getElementById("btn").addEventListener("click", hello);
</script>
Example 4: 'this' in an arrow function
<button id="btn">Click Me!</button>

<p id="demo"></p>

<script>
let hello = "";

hello = () => {
document.getElementById("demo").innerHTML += this;
}

//The window object calls the function:
window.addEventListener("load", hello);

//A button object calls the function:
document.getElementById("btn").addEventListener("click", hello);
</script>
  • exercise: modify the example above
  • exercise: try running Example 1 and 2 below (modified from digitalocean):
    • Note:
      • in Example 1: document.write('\n') does not work in the code below: In HTML, all whitespace (including newlines) is collapsed and treated as a single space. stackoverflow
      • in Example 1: <br/> is the XHTML version of <br>. Since you're not using XHTML, you would just use <br>. (How do I know you're not using XHTML? Because you're using document.write, which you can't use in XHTML.) stackoverflow
Example 1: 'this' in arrow functions
<script>
const whoAmI = {
name: 'Leslie Knope',
regularFunction: function() {
document.write(this.name + '<br/>')
},
regularFunction2: function() {
document.write(this.name + '\n') // This does not work! The newline is not printed!
},
arrowFunction: () => {
document.write(this)
},
}

whoAmI.regularFunction() // "Leslie Knope"
whoAmI.regularFunction2() // "Leslie Knope"
whoAmI.arrowFunction() // [object Window]
</script>
Example 2: 'event.currentTarget', 'this' in arrow functions
<script>

const button = document.createElement('button')
button.textContent = 'Click me'
document.body.append(button)

class Display {
constructor() {
this.displayString = 'New text'

// In an arrow function "this" always refers to the context (=object) in which the
// arrow function was defined, ie. here the "Display" class.
const changeText = event => {
event.target.textContent = this.displayString;
}

button.addEventListener('click', getText)
button.addEventListener('click', changeText)

// Here, "this" refers to the "event.currentTarget" object, ie. "button" which
// is outside of the "Display" class.
function getText(event) {
document.getElementById("demo").innerHTML += this.textContent
}
}
}

new Display()

</script>

Sidenote about Example 2:

  • Why can we call getText() before it is defined?
  • Why can we not call changeText() before it is defined?
  • answer: see stackoverflow

TypeScript (Microsoft)​

  • a strict syntactical superset of JavaScript
  • adds optional static typing to the language
  • designed for the development of large applications
  • transpiles to JavaScript
  • As it is a superset of JavaScript, existing JavaScript programs are also valid TypeScript programs.
  • developed and maintained by Microsoft

Web APIs​

mdn list of Web APIs

"Web APIs are typically used with JavaScript, although this doesn't always have to be the case."

"JavaScript has application programming interfaces (APIs) for working with text, dates, regular expressions, standard data structures, and the Document Object Model (DOM)." "JavaScript" Wikipedia

TODO​

w3schools

DOM​

One Web API.

Interfaces​

Element​
Instance Properties​
  • .innerHTML gets or sets the HTML or XML markup contained within the element. mdn
Event​
Syntax​

HTML Events

<button onclick="activateLasers()">
Activate Lasers
</button>

JavaScript Events

  • either: object.onclick = function(){myScript};
  • or: object.addEventListener("click", myScript); ( see .addEventListener() )

React Events

  • React events are named using camelCase, rather than lowercase.
  • With JSX you pass a function as the event handler, rather than a string.
  • e.g. <button onClick={function}>
event Object​

event

  • One can access the current event through window.event. Just using event is implicitly accessing window.event. stackoverflow
  • a global variable
event.target, event.currentTarget​
  • .currentTarget: doc
    • "always refers to the element to which the event handler has been attached, as opposed to Event.target, which identifies the element on which the event occurred and which may be its descendant."
  • .target: doc
    • "a reference to the object onto which the event was dispatched."

"We're using event.target to get the element that was the target of the event (that is, the innermost element). If we wanted to access the element that handled this event (in this case the container) we could use event.currentTarget." mdn: note below this section

"Here you can see we are including an event object, e, in the function, and in the function setting a background color style on e.target — which is the button itself. The target property of the event object is always a reference to the element the event occurred upon. So, in this example, we are setting a random background color on the button, not the page." mdn

  • "Note: You can use any name you like for the event object — you just need to choose a name that you can then use to reference it inside the event handler function. e/evt/event is most commonly used by developers because they are short and easy to remember. It's always good to be consistent - with yourself, and with others if possible."
onClick (Event)​
  • in React notation: <button onClick={function}>
Event Handler​
  • some_element.addEventListener() method
    • The addEventListener() method attaches an event handler to the specified element.
    • The addEventListener() method attaches an event handler to an element without overwriting existing event handlers.
    • You can add many event handlers to one element.
    • You can add many event handlers of the same type to one element, i.e two "click" events.
    • You can add event listeners to any DOM object not only HTML elements. i.e the window object.

Fetch API​

Send a DELETE Request​

  • run the following JavaScript statement using the DevTools/JavaScript Console of your browser
warning

In Firefox before running the following JavaScript code you have to (temporarily) disable devtools.jsonview.enabled in about:config, otherwise Content Security Policy (CSP) will block this request, stackoverflow

JavaScript Fetch API DELETE Request
(async function deletePhoto(id) {
await fetch("http://localhost:8080/photoz/" + id, {
method: "DELETE"
})
})("5")

Libraries​

jQuery​

jQuery is a JavaScript library designed to simplify HTML DOM tree traversal and manipulation, as well as event handling, CSS animations, and Ajax. It is free, open-source software using the permissive MIT License. As of August 2022, jQuery is used by 77% of the 10 million most popular websites. Web analysis indicates that it is the most widely deployed JavaScript library by a large margin, having at least three to four times more usage than any other JavaScript library.

jQuery's syntax is designed to make it easier to navigate a document, select DOM elements, create animations, handle events, and develop Ajax applications. jQuery also provides capabilities for developers to create plug-ins on top of the JavaScript library. This enables developers to create abstractions for low-level interaction and animation, advanced effects and high-level, theme-able widgets. The modular approach to the jQuery library allows the creation of powerful dynamic web pages and Web applications.

Setup​

warning

Prefer using CDNs when possible. See ()

w3schools

Google CDN:

<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
</head>

Downloading jQuery:

There are two versions of jQuery available for downloading:

  • Production version - this is for your live website because it has been minified and compressed
  • Development version - this is for testing and development (uncompressed and readable code)

Both versions can be downloaded from jQuery.com.

The jQuery library is a single JavaScript file, and you reference it with the HTML <script> tag (notice that the <script> tag should be inside the <head> section):

<head>
<script src="jquery-3.7.1.min.js"></script>
</head>

Tip: Place the downloaded file in the same directory as the pages where you wish to use it.

Shortcuts​

Cheatsheet​

Performance​

CDN vs Locally Stored Scripts​

stackoverflow:

The benefit of a CDN is not (and should not be) for you. It is for your customers / users. Using CDN files - especially for widely used libraries like jQuery (or any other big library) - means they will receive a cached copy of the file from a physical location near them. In most cases, using a popular CDN for big libraries means the user has also downloaded that resource before - from someone else's site - so the file will be cached locally in their browser.

This helps reduce the time your user spends downloading files. It is not about your server load or your development ability in all but the smallest margin of edge cases. Think about your users first!

Using a CDN for most static files is strictly better for your users.

UPDATE: Browsers No Longer Support Cross-site Caching

As of 2022-01-25

It's worth noting that while this was true for a long time, it's really not the case anymore. There are still real benefits from using CDNs (for example: files are served from a location in close physical proximity to the consuming end-user - on large, globally distributed CDNs), but the cross-domain resource caching is no longer a benefit.

@x-yuri noted this near the end of 2021, and all the major browsers implemented cache partitioning no later than 2020.

It is still beneficial to use a CDN, and it is still for your users' benefit, but the benefit is in reduced latency with geo-located servers, not in general performance due to a hot cache hit.

stackoverflow:

If you mean the core jQuery libraries, use the google CDN for an internet-facing site (as opposed to an internal one).

The CDN has the following advantages you'll find hard to compete with:

  • More servers
  • The bandwidth (you don't pay for)
  • Geolocation (lower response time)
  • Redundancy
  • The optimized caching settings
  • Chance the user has already cached the file from there
  • Parallelized downloads, user can grab other content from your site at the same time

Though you can configure the cache headers just like they do, you probably can't serve the file faster. That being said, the library/CDN is only part of the puzzle. Miscellaneous plugins and code you have should also be minified, combined and served via gzip.

comments:

  • Awesome answer Nick, but what if CDN-served libraries are updated and suddenly it breaks the layout or similar? Isn't that a security breach? – dzhi
  • @purpler - You have control there, for example you can reference a specific version which won't change, e.g. http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js, or the latest dot/minor version: http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.js, or the latest major version: http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.js (make sure to use jquery.min.js in production!)

Minification​

Tools for Minification:

  • jsDelivr CDN can also minify any file in JavaScript, CSS, or SVG format, which can reduce loading times. (source)

Wikipedia:

"The process of removing all unnecessary characters from the source code of interpreted programming languages or markup languages without changing its functionality."

"These unnecessary characters usually include white space characters, new line characters, comments, and sometimes block delimiters, which are used to add readability to the code but are not required for it to execute."

"Minification reduces the size of the source code, making its transmission over a network (e.g. the Internet) more efficient."