JavaScript
JavaScript (aka ECMAScript aka ES)
Versions, Revisions
- ES6 = ECMAScript 6 = ECMAScript 2015
- arrow functions
Crash Course
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
JavaorC#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.
- JIT compilation aka dynamic compilation ( source )
- 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
javascriptsyntax highlighting usingnvim-treesitter. - Install
javascriptformatting usingcoc-prettier.
CDNs
CDN: A content delivery network, or content distribution network.
Common CDNs
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
- e.g.
- jsDelivr
- e.g.
cdn.jsdelivr.net - official CDN of Bootstrap
- e.g.
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
thisbindings, etc
Variables
let
- only use this, if you know the variable will change, otherwise use
const- makes the code more robust
const
- 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).
- can't be changed through reassignment (i.e. by using the assignment operator
- 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
totalfrom 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
undefinedas the first argument totoLocaleStringto use the system locale rather than specifying a locale
Arrays
Spread
I.e. ... notation, e.g.
const cart = [...state.cart];
Use cases:
- instead of
const concatArray = array1.concat(array2)useconst 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])(modifiesarray1) useconst pushedArray = [...array1, array2](does not modifyarray1) - 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
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
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
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
xin anarray1 - return
-1ifxis 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.
- incorrect, see comment under this stackoverflow answer
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
thisrefers 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
thisrefers to the object that the function is executed in., blog.kevinchisholm.com - in an arrow function: You cannot rebind
thisin an arrow function. It will always be defined as the context in which it was defined. If you requirethisto be meaningful you should use a normal function. stackoverflow
w3schools (scroll down to section "What About this?")
- In regular functions the
thiskeyword represented the object that called the function, which could be the window, the document, a button or whatever. - With arrow functions the
thiskeyword always represents the object that defined the arrow function.
- When a function executes in the global context,
thisrefers to the global, orwindowobject - When a function is a method of an Object,
thisrefers 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),
thisrefers to the object whose context within which it is executed - When you instantiate a constructor function, inside of the instance object,
thisrefers 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
thiswill represent different objects depending on how the function was called
- shows that for a regular function
- Example 4: with arrow function
- shows that for an arrow function it does not matter who is the caller,
thiswill always be the the object that owns the function, no matter who calls the function
- shows that for an arrow function it does not matter who is the caller,
<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>
<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 usingdocument.write, which you can't use in XHTML.) stackoverflow
- in Example 1:
- Note:
<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>
<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
"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
DOM
One Web API.
Interfaces
Element
Instance Properties
.innerHTMLgets 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 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 usingeventis implicitly accessingwindow.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."
- "always refers to the element to which the event handler has been attached, as opposed to
.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/eventis 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.
- The
Fetch API
Send a DELETE Request
- run the following JavaScript statement using the DevTools/JavaScript Console of your browser
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
(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
Prefer using CDNs when possible. See ()
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
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.
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 usejquery.min.jsin production!)
Minification
Tools for Minification:
- jsDelivr CDN can also minify any file in JavaScript, CSS, or SVG format, which can reduce loading times. (source)
"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."