JavaScript / ECMAScript (by Brendan Eich 1995) is an ECMA standard since 1997, ECMAScript is the official name of the language.
ES version | ECMA | Name |
---|---|---|
ES5 | - | ECMAScript 2009 |
ES6 | - | ECMAScript 2015 |
ES7 | - | ECMAScript 2016 |
ES8 | - | ECMAScript 2017 |
ES9 | - | ECMAScript 2018 |
ES10 | ECMA-262 | ECMAScript 2019 |
Transpile via Babel
Babel is a toolchain that is mainly used to convert ECMAScript 2015+ code into a backwards compatible version of JavaScript in current and older browsers or environments.
ES6 | ES5
-----------------+--------------------
const a = 123; | "use strict";
| var a = 123;
-----------------+--------------------
Values: primitive / reference
debug via console API
- console.clear(): clear console
- console.log() / .debug() / .warn() / .error(): use %c directive to apply CSS style
console.warn("abc");
console.log("%s %d", "int", 1.555);
console.log("%s %.1f", "float", 1.555);
console.error("Error %o: ", { keyA: 'valA', keyB: 123, keyC: ["a", "b", "c"] } );
console.log('%c big ABC', 'font-size:x-large;color:#f00;')
- console.table():
console.table({ keyA: 'valA', keyB: 123, keyC: ["a", "b", "c"] } );
- console.dir(): prints interactive list of object properties
console.dir({ keyA: 'valA', keyB: ["a", "b", "c"] } );
- console.group() / .groupEnd() / .groupCollapsed():
console.log("START");
console.groupCollapsed("group 1") ; console.log("1 a") ; console.log("1 b") ; console.groupEnd();
console.log("END");
- console.count() / .countReset(): log number of times this line has been called (with the given label)
console.count("count a");
- console.time() / .timeEnd()
const longArray = Array.from({ length: 10000000 }, (_, i) => i);
console.time("forof-loop");
for (const value of longArray) {;}
console.timeEnd("forof-loop");
console.time("for-loop");
for (let i = 0; i < longArray.length; i++) {;}
console.timeEnd("for-loop");
console.time("foreach-loop");
longArray.forEach(element => {;});
console.timeEnd("foreach-loop");
- console.memory: heap size status
var, let and const
Before ES6: only var was available! Since ES6 const and let: let is block scoped, no need for var anymore!
That means that a variable created with the let keyword is available inside the “block” that it was created in as well as any nested blocks. When I say “block”, I mean anything surrounded by a curly brace {} like in a for loop or an if statement.
- var: function scoped ; undefined when accessing a variable before it's declared
- let: block scoped ; ReferenceError when accessing a variable before it's declared
- const: block scoped ; ReferenceError when accessing a variable before it's declared ; can't be reassigned
Arrow => functions
Arrow functions are a concise method of declaring anonymous functions in JS.
Arrow function inherit this from the scope they were defined in.
// vanilla anonymous function
someMethod(1, function () { // has no name
console.log('called');
});
// anonymous arrow function
someMethod(1, () => { // has no name
console.log('called');
});
this keyword
this points to the surrounding execution context == "on what the function was called"
const myButton = document.querySelector('some-button');
myButton.addEventListener('click', function() {
console.log(this); // => this refer to the element on which the event occurs
});
Visibility of variables - scope
-
global: variables defined outside of any function or block statement
-
function: var variables defined inside of a function
-
block: let / const variables defined inside an block
Closure
In JavaScript every function closes over its environment on creation
Anonymous Closures A anonymous function which executes immediately. All code that runs inside the function lives in a closure, which provides privacy and state throughout the lifetime of the application.
(function () {
// ... all vars and functions are in this scope only
// still maintains access to all globals
}());
var test;
function fDelay() {
setTimeout(function () {
alert('test=' + test);
}, 2222);
}
test = 'abc';
fDelay();
test = 'xyz';
// => alert: test=xyz
// because the value is looked up when needed and not when the closure is created
Callback, promises, async/await
JavaScript is single-threaded, that means only capable of doing one thing at the same time -> asynchronous tasks are handled by it's environment (web browser, NodeJS runtime, ...)
The biggest advantage of Promises over callbacks is readability and chainability.
An async function is 'just' a fancy promise wrapper, which means, the async/await code and the Promise code, are functionally equivalent.
setTimeout(callFunction, 5000); // callback function handed over to the web browser
Promises | pure callback
-------------------------------+------------------------------------
fetch('data.com/abc') | fetch('data.com/abc')
.then(response => { | response => {
return response.json(); | response.json(data => {
}) | console.log(data);
.then(data => { | // other nested callbacks
console.log(data); | });
}) | },
.catch(e => { | e => {
console.error(e); | console.error(e);
}); | }
| );
-------------------------------+------------------------------------
async function makeHttpRequest(url) { ... }
try {
const data = await makeHttpRequest('data.com/abc');
console.log(data);
} catch (e) {
console.error(e);
}
Iterating DOM elements
- for loop: supported in all browsers
const allimg = document.querySelectorAll("img");
const allimgLen = allimg.length;
for (var i = 0; i < allimgLen; i++) {
console.log('image: ', allimg[i]);
}
- forEach loop: supported in modern browsers, but not in IE11 and below
const allimg = document.querySelectorAll("img");
allimg.forEach(actimg => {
console.log('image: ', actimg);
});
- for-of loop: in modern browsers, but not in IE11 and below
const allimg = document.querySelectorAll("img");
for (const actimg of allimg) {
console.log('image: ', actimg);
}
- for-of {values()|entries()|keys()} loop: iterators are ES2015 specific
const allimg = document.querySelectorAll("img");
for (const actimg of allimg.values()) {
console.log('image: ', actimg);
};
Iterating objects
- for…in loop => fastest version
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
console.log(key + " -> " + obj[key]);
}
}
- Object.keys => slower than for…in
Object.keys(obj).forEach(function (key) {
console.log(key + " -> " + obj[key]);
});
Object.keys(obj).forEach(key => {
console.log(key + " -> " + obj[key]);
});
- Object.entries => slowest
Object.entries(obj).forEach(entry => {
console.log(entry[0]+ " -> " + entry[1]);
});
- Object example
var obj= {
keyA: 'valueA',
keyB: 'valueB',
keyC: 123,
fPrintData: function() {
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
if ((typeof obj[key] === 'string') || (typeof obj[key] === 'number')) {
console.log(key + " -> " + obj[key]);
}
}
}
}
};
// ---
var keyName1="myKey1";
var obj= {
[keyName1]: 'valueA',
keyB: 'valueB',
keyC: 123,
keyD: ["a", "b", "c"]
};
console.table(obj);
console.log(JSON.stringify(obj,null,2));
console.log(obj);
Float Precision
var a=-0.34;
var b=1.20;
x=(a+b);
alert(x);
alert(x.toPrecision(10));
alert((x.toPrecision(10)).replace(/0*$/, ''));
Load image and set background of element
var aElem, elemStyle, imgSrc, image;
aElem = document.getElementById("someElementId");
elemStyle = elem.style;
imgSrc = "someImageWithPath.jpeg";
image = new Image();
image.onload = function () {
setTimeout(function () {
elemStyle.backgroundImage = "url(" + imgSrc + ")";
elemStyle.backgroundPosition = "0 0";
image = null;
}, 111);
};
image.src = imgSrc;
Event delegation on non-bubbling events
events like focus, blur, load, unload, change, reset, scroll,... need third argument of addEventListener "useCapture" to capture events that happen in the parent. Following example does not work without true at the end!
document.addEventListener('focus', function (event) {
console.log('something came into focus: ' + event.target);
}, true);
Vanilla JavaScript version of "run on DOM ready"
function fVanillaJsDomReady(fn) {
if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading") {
fn();
} else {
document.addEventListener("DOMContentLoaded", fn);
}
}
fVanillaJsDomReady(function () {
console.log("DOM ready ...");
}
Testing existence of property
// BAD: This will cause an error in code when foo is undefined
if (foo) {
doSomething();
}
// GOOD: This doesn't cause any errors. However, even when
// foo is set to NULL or false, the condition validates as true
if (typeof foo != "undefined") {
doSomething();
}
// BETTER: This doesn't cause any errors and in addition
// values NULL or false won't validate as true
if (window.foo) {
doSomething();
}
function: object destructuring with default parameter
function fDoSomething({pVal1, pVal2, pTime = 'today'}) {
return `${pVal1} ${pVal2} -> time=${pTime}?`;
}
fDoSomething({
pVal1: 'aaa',
pVal2: 'bbb'
});
JavaScript arguments
</details>
<details><summary><strong>"random" numbers</strong></summary>
```javascript
let maxVal = 99;
for (let i = 0; i < 11; i++) {
setTimeout(() => console.log("random value " + i + ": " + (new Date() % maxVal) + " / " + (Math.floor(Math.random()*maxVal))), 1000)
}
events bound in all elements on page
Array.from(document.querySelectorAll('*'))
.reduce(function(pre, dom){
var evtObj = getEventListeners(dom)
Object.keys(evtObj).forEach(function (evt) {
if (typeof pre[evt] === 'undefined') {
pre[evt] = 0
}
pre[evt] += evtObj[evt].length
})
return pre
}, {})
Date / toLocaleString
var dm= Date.now(); // number of milliseconds elapsed since January 1, 1970 00:00:00 UTC.
var d= new Date();
var opt = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric', hour12: false };
opt.timeZone = 'UTC';
opt.timeZoneName = 'short';
console.log(": milliseconds since 1.1.1970 ", dm);
console.log(": current Date()=", d);
console.log(": UTC time zone diff to local machine time=", d.getTimezoneOffset());
console.log(": A: ", d.toLocaleString(navigator.language || 'de-DE', opt));
console.log(": B: ", d.toString());
console.log(": C: ", d.toDateString());
console.log(": D: ", d.toGMTString());
console.log(": E: ", d.toLocaleDateString());
console.log(": F: ", d.toISOString());
console.log(": G: ", d.toTimeString());
format numbers (currency)
var number = 123456.78987654321;
console.log(number.toLocaleString('de-DE', { style: 'currency', currency: 'EUR', maximumFractionDigits: 4 }));
Template literals
enclosed by the backtick ` (grave accent) character instead of double or single quotes.let a = 10;
let b = 20;
console.log(`a=${a} b=${b} =>
SUM=${a + b}`);
//---
console.log(String.raw`Hi\n${2+3}!`);
External documentation
Markdown test (click to expand)
😄 😕 👍 👎 🌐 ⏱️ 📲 💻 ⌨️ 📘 📧 📝 ⬆️ ➡️ 🔝 🔚
bold italic strikethrough
Color Syntax
block quote
block quote (2 depth)
block quote (3 depth)
- list
- list indented
- ordered
- list
- ordered list
- indented
- task
- list completed
inline code
code block
console.log("fenced code block");
**HTML block**
table | head |
---|---|
table | body |