JavaScript - ttulka/programming GitHub Wiki
- Automatic semicolon insertion (ASI) will take effect in the presence of a newline.
- Any variable that you declare is by default defined in global scope.
- As a global variable is visible in all other scopes, a global variable can be modified by any scope.
- No block-level scope; instead, function-level scope.
var a = 1;
(function() {
var a = 2;
console.log( a ); // 2
})();
console.log( a ); // 1
-
let
keyword to introduce traditional block scope (ES6).
var myv = 1;
let myl = "a";
const myc = true;
{
var myv = 2;
let myl = "b";
const myc = false;
console.log(myv + " " + myl + " " + myc);
myv = 3;
myl = "c";
// myc = true; /* cannot redefine a constant */
console.log(myv + " " + myl + " " + myc);
}
console.log(myv + " " + myl + " " + myc);
prints:
2 b false
3 c false
3 a true
const key = 'name'
const user = {
[key]: 'Tomas',
}
console.log(user) // { name: 'Tomas' }
Only var
variables are partialy hoisted (only the variable name, not its value), functions are fully hoisted, let
and const
variables are not hoisted.
// prints Hello!
function a(){ console.log('Hi!') }
a();
function a(){ console.log('Hello!') }
Wherever a var appears inside a scope, that declaration is taken to belong to the entire scope and accessible everywhere throughout.
a = 2
var a
console.log(a) // 2
console.log(a) // undefined
var a = 2
var a = 2;
foo(); // works because `foo()` function declaration is "hoisted"
function foo() {
a = 3;
console.log( a ); // 3
var a; // declaration is "hoisted" to the top of `foo()`
}
console.log( a ); // 2
Function declarations are hoisted, but function expressions are not:
foo(); // TypeError
bar(); // ReferenceError
var foo = function bar() { ... }
The variable identifier foo
is hoisted and attached to the enclosing scope (global) of this program, so foo()
doesn’t fail as a ReferenceError
. But foo
has no value yet (as it would if it had been a true function declaration instead of expression). So, foo()
is attempting to invoke the undefined
value, which is a TypeError
illegal operation.
Hoisting happends on every execution context:
var a = 'A';
function f() {
console.log('1: a is', a); // 1: a is undefined
var a = 'AA';
console.log('2: a is', a); // 2: a is AA
}
f();
Absence of meaningful values is indicated by two special values — null
, when the non-value is deliberate, and undefined
, when the value is not assigned to the variable yet.
var xl; // undefined
xl; // undefined
xl; // undefined
null == undefined; // true
An “undefined” variable is one that has been declared in the accessible scope, but at the moment has no other value in it. By contrast, an “undeclared” variable is one that has not been formally declared in the accessible scope.
With default parameters, undefined will use the default while null does not:
let logHi = (str = 'hi') => {
console.log(str);
}
logHi(undefined);
// hi
logHi(null);
// null
- Prefer
undefined
tonull
(null
is a bad idea).
// this is a safe existence check
if (typeof DEBUG !== "undefined") {
console.log( "Debugging is starting" );
}
- Variables must be explicitly declared
- The with statement is not allowed.
- Octal literals are not allowed (eg.
010 === 8 true
)
'use strict';
var decimal = 6;
var hex = 0xf00d;
var binary = 0b1010;
var octal = 0o744;
-
Number.MIN_VALUE
andNumber.MAX_VALUE
;Number.MAX_SAFE_INTEGER
andNumber.MIN_SAFE_INTEGER
-
Number.parseInt' and
Number.parseFloat' -
Number.NaN
andNumber.isNaN
isNaN(NaN); // true
NaN == NaN; // false
isNaN("elephant"); // true
NaN + 5; // NaN
-
Math.E
,Math.PI
,Math.LOG10E
,Math.LOG2E
-
Math.abs
,Math.pow
,Math.sqrt
,Math.min
,Math.max
,Math.trunc
,Math.round
,Math.ceil
,Math.floor
-
Math.random
<0;1)
Math.random(); // 0.24329434322856125
Math.floor(Math.random() * Math.floor(5)); // 0,1,2,3,4
In JavaScript, binary floating point numbers do not map correctly to Decimal numbers:
.1 + .2 // 0.30000000000000004
- For true decimal math use
big.js
- Sequence of Unicode characters (each 16 bit)
- Quotes
'
and double quotes"
are equivalent. - Apostrophes (Grave accent) allows multiline-strings and variables resolution.
console.log(`Value: ${obj.value}`);
- Strings are not just arrays of characters. Strings are immutable while arrays mutable.
"foo".repeat(3) // foofoofoo
"bar".startsWith("b") // true
"bar".endsWith("r") // true
"bar".includes("a") // true
The following rules govern what becomes false (falsy values) and what turns out to be true (truthy values):
-
false
,0
(and"0"
), the empty string (""
),NaN
,null
, andundefined
are represented asfalse
- everything else is
true
var oFalse = new Boolean(false);
var pFalse = false;
oFalse; // [Boolean: false]
pFalse; // false
oFalse == pFalse; // true
oFalse === pFalse; // false
if (pFalse) "It's true!" // undefined
if (oFalse) "It's true (but don't believe it)!" // It's true (but don't believe it)!
if (oFalse.valueOf()) "It false!" // undefined
typeof oFalse; // object
oFalse instanceof Boolean; // true
typeof pFalse; // boolean
pFalse instanceof Boolean; // false
var a = new Boolean(false)
var b = new Number(0)
var c = new String("")
var d = Boolean( a && b && c ) // true
a || b // roughly equivalent to: `a ? a : b`
a && b // roughly equivalent to: `a ? b : a`
The &&
operator “selects” the second operand if and only if the first operand tests as truthy, and this usage is sometimes called the “guard operator” -- the first expression test “guards” the second expression:
foo = () => console.log( a )
var a = 42
a && foo() // 42
-
==
tries to do type coercion between two variables.
"" == "0" // false
0 == "" // true
"" === "0" // false
0 === "" // false
- Always use
===
and!==
except for null checks
null == null // true
null == undefined // true
0 == null // false
'' == null // false
false == null // false
null === null // true
null === undefined // false
0 === null // false
'' === null // false
false === null // false
[] == ![] // true -- before is even processed, it’s actually already translated to `[] == false`
0 == "\n" // true -- with empty "", "\n" (or " " or any other whitespace combination) is coerced to 0
42 == "43" // false
"foo" == 42 // false
"true" == true // false
42 == "42" // true
"foo" == ["foo"] // true
- If either side of the comparison can have
true
orfalse
values, never use==
- If either side of the comparison can have
[]
,""
, or0
values, consider not using==
{a:123} == {a:123} // false
{a:123} === {a:123} // false
import * as deepEqual from "deep-equal";
console.log(deepEqual({a:123},{a:123})); // true
The spec says for a <= b
, it will actually evaluate b < a
first, and then negate that result. Since b < a
is also false
, the result of a <= b
is true
:
var a = { b: 42 }
var b = { b: 43 }
a < b // false
a == b // false
a > b // false
a <= b // true
a >= b // true
JavaScript store dates as the number of milliseconds since January 1, 1970, 00:00:00.
new Date() /* today */ // 2018-03-11T14:05:50.094Z
new Date(2000, 1, 25) // 2000-02-24T23:00:00.000Z
new Date(2000, 1, 25, 10, 20, 30, 444) // 2000-02-25T09:20:30.444Z
Date.now() // 1520777339877
Date.now() // 1520777340140
-
get/setFullYear
,get/setMonth
,get/setDate
,get/setHours
,get/setMinutes
,get/setSeconds
(and sets) get/setTime
There are many ways how to create a function:
-
named function declaration:
function first(...) {...};
-
anonymous function expression:
var second = function(...) {...};
-
named function expression:
var third = function someName(...) {...};
-
function constructor:
var fifth = new Function(...);
-
arrow function:
var sixth = (...) => {...};
-
Immediately invoked function expression (IIFE)
// prints `hello!` immediately.
(function() {
console.log("hello!");
})();
- The
this
parameter refers to an object that's implicitly associated with the function invocation, termed as a function context.
var santa = {
say: function() {
console.log("ho ho ho");
}
}
santa.say();
function eventHandler(event){
event();
}
eventHandler(function(){
console.log("Event fired");
});
function sum(a=0, b=0){
return (a + b);
}
console.log(sum(9,9)); // 18
console.log(sum(9)); // 9
- Lexically captures the meaning of
this
. - Lexically captures the meaning of
arguments
.
console.log(( x => x * 3 )( 3 )); // 9
var f1 = () => console.log("Hello!");
f1(); // Hello!
var multiply = (a,b) => a * b;
console.log(multiply(2,2)); // 4
var multiply = (x,y) => {
if(x != 0 && y != 0) {
return x * y;
}
}
console.log(multiply(2,2)); // 4
Inside an arrow function this
is always the calling context.
let f = () => {
return { name: "Tomas" };
}
// could be written:
let f = () => ({ name: "Tomas" })
f() // { name: 'Tomas' }
The spread operator expands an expression in places where you would otherwise require multiple arguments, elements, or variables.
function sum3(a, b, c) { return a + b + c; }
const x = [1, 2, 3];
const y = sum3(...x); // 6
const numbers = [2, 2, 9, 6, 0, 1, 2, 4, 5, 6];
const maxArray = arr => Math.max(...arr);
const maxA = maxArray(numbers); // 9
A generator is a special kind of function that can start and stop one or more times, and doesn't necessarily ever have to finish.
function *foo() {
x++
yield // pause!
console.log( "x:", x )
}
function bar() {
x++
}
var x = 1
// construct an iterator `it` to control the generator
var it = foo()
// start `foo()` here!
it.next()
x // 2
bar()
x // 3
it.next() // x: 3
function* dummyGenerator() {
yield 1;
yield 2;
yield 3;
}
var gen = dummyGenerator();
gen.next().value; // 1
gen.next().value; // 2
gen.next().value; // 3
gen.next().value; // undefined
function *foo(x) {
var y = x * (yield)
return y
}
var it = foo( 6 )
it.next()
var res = it.next( 7 )
res.value // 42
The key concept is that when you define a function, it can refer to not only its own local variables, but also to everything outside of the context of the function:
function newCounter() {
let count = 0;
return function() {
return ++count;
};
}
const nc = newCounter();
console.log(nc()); // 1
console.log(nc()); // 2
console.log(nc()); // 3
var v = 1
function a() {
function b() {
console.log(v)
}
return b
}
var f = a()
f() // 1
v = 2
f() // 2
for (var i = 0; i < 10; i++) {
setTimeout(function() { console.log(i); }, 100 * i);
}
// 10 10 10 10 10 10 10 10 10 10
for (let i = 0; i < 10 ; i++) {
setTimeout(function() { console.log(i); }, 100 * i);
}
// 0 1 2 3 4 5 6 7 8 9
sum3 = x => y => z => x + y + z;
sum3(1)(2)(3); // 6
const multiply = (a,b) => a*b
const multiplyByTwo = multiply.bind(this, 2)
multiplyByTwo(5) // 10
Modules are used to mimic classes and focus on public and private access to variables and functions.
var moduleName = (function() {
// private state
// private functions
return {
// public state
// public variables
}
})()
// module1.js
export function myfn1() { ... }
// module2.js
export default function myfn2() { ... }
// module3.js
export default function myfn3A() { ... }
export function myfn3B() { ... }
<!-- index.html -->
<script type="module">
import { myfn1 } from './module1.js';
import myfn2 from './module2.js';
import myfn3A, { myfn3B } from './module3.js';
</script>
JavaScript never shares data across threads, the function code is atomic - "run-to-completion" behaviour.
Asynchrony is implemented by a jobs queue.
console.log('A')
setTimeout(() => console.log('B'), 0)
console.log('C')
// A C B
-
Synchronous callback is invoked before a function returns, that is, while the API receiving the callback remains on the stack. An example might be:
list.foreach(callback)
whenforeach()
returns, you would expect that the callback had been invoked on each element. -
Asynchronous or deferred callback is invoked after a function returns, or at least on another thread’s stack. Mechanisms for deferral include threads and main loops (other names include event loops, dispatchers, executors). Asynchronous callbacks are popular with IO-related APIs, such as
socket.connect(callback)
you would expect that whenconnect()
returns, the callback may not have been called, since it’s waiting for the connection to complete.
Callbacks should be either always sync or always async, as a documented part of the API contract - "Don't release Zalgo!"
In this example, the result (0 or 1) depends on conditions (sync or async callback invocation):
function callback(data) {
console.log(a)
}
var a = 0
ajax(url, callback)
a++
const promisify = fn => (...args) => new Promise((resolve, reject) =>
fn(...args, (err, data) => (err ? reject(err) : resolve(data)))
);
promisify(/* do something expensive */)
.then(data => /* success 1 */)
.then(data => /* success 2 */)
.catch(err => /* error */) // catchs only error happened before
.then(data => /* success 3 */)
;
function wait(ms) {
return new Promise(function (resolve, reject) {
setTimeout(resolve, ms)
})
}
Promise.resolve('Success').then(function(value) {
console.log(value); // "Success"
});
Promises are handled by the Job Queue in the JavaScript Runtime (browser, Node.js) which has higher priority than the Callback Queue (used for setTimeout
) for the Event Loop:
setTimeout(()=>console.log(1), 0)
Promise.resolve(2).then(console.log)
console.log(3)
// 3 2 1
- The
async
function declaration defines an asynchronous function, which returns anAsyncFunction
object. - The
await
operator is used to wait for a Promise. It can only be used inside anasync
function.
function resolveAfter2Seconds(x) {
return new Promise(resolve => {
setTimeout(() => { resolve(x); }, 2000);
});
}
async function f1() {
var x = await resolveAfter2Seconds(10);
console.log(x); // 10
}
f1();
await
is not a no-op. If the awaited thing is not a promise, it is wrapped in a promise, that promise is awaited. Therefore await
changes the execution order:
// prints 1,2,3
console.log(1);
(async function() {
var x = await null; // remove await to see 1,3,2
console.log(3);
})();
console.log(2);
this
is the object that the function is a property of.
this
represents the function’s context.
this
is an implicit input.
When this
is used, we need to always call the function with call()
or apply()
and pass in the context object.
While it may often seem that this
is related to “object-oriented patterns,” in JS this
is a different mechanism.
If a function has a this
reference inside it, that this
reference usually points to an object. But which object it points to depends on how the function was called.
-
this
does not refer to the function itself.
function say(thing) {
console.log(this + ' says ' + thing);
}
say.call("John", "hello"); // John says hello
say("hello"); // [object global] says hello - Node.js == say.call(global, "hello");
// [object Window] says hello - HTML browser == say.call(window, "hello");
var person = {
say: function(thing) {
console.log(this + ' says ' + thing);
}
say2: (thing) => {
console.log(this + ' says ' + thing);
}
};
person.say("hello"); // [object Object] says hello == person.say.call(person, "hello");
person.say2("hello"); // [object global] says hello - Node.js == person.say.call(global, "hello");
// [object Window] says hello - HTML browser == person.say.call(window, "hello");
class Person {
say(thing) {
console.log(this + ' says ' + thing);
}
}
var person = new Person();
person.say("hello"); // [object Object] says hello == person.say.call(person, "hello");
When using arrow function, the lexical scope is preserved so this
is referring to the context in which translated object has defined in, not the the actual object that holds the reference to the function.
var arr = new Array(1,2,3)
var arr = Array(1,2,3)
var arr = [1,2,3]
var a = Array( 3 )
a.length // 3
a[0] // undefined
var b = Array.of( 3 )
b.length // 1
b[0] // 3
var c = Array.of( 1, 2, 3 )
c.length // 3
c // [1,2,3]
// array-like object
var arrLike = { length: 3, 0: "foo", 1: "bar" }
var arr = Array.from( arrLike ) // [ 'foo', 'bar', undefined ]
var arrCopy = Array.from( arr ) // [ 'foo', 'bar', undefined ]
var myArray = new Array("1", "2", "3");
var last = myArray.pop();
// myArray = ["1", "2"], last = "3"
var myArray = new Array("1", "2");
myArray.push("3");
// myArray = ["1", "2", "3"]
var a = [ ];
a[0] = 1;
// no `a[1]` slot set here
a[2] = [ 3 ];
a[1]; // undefined
a.length; // 3
Arrays are numerically indexed, but they also are objects that can have string keys/properties added to them (but which don’t count toward the length of the array):
var a = [ ];
a[0] = 1;
a["foobar"] = 2;
a.length; // 1
a["foobar"]; // 2
a.foobar; // 2
However, if a string value intended as a key can be coerced to a standard base-10 number, then it is assumed that you wanted to use it as a number index rather than as a string key:
var a = [ ];
a["13"] = 42;
a.length; // 14
var colors = ['Red', 'Blue', 'Yellow'];
console.log(colors.length); // 3
colors.length = 2;
console.log(colors); // ["Red","Blue"] - Yellow has been removed
colors.length = 0;
console.log(colors); // [] the colors array is empty
colors.length = 3;
console.log(colors); // [undefined, undefined, undefined]
colors.forEach(function(color) {
console.log(color);
});
var myArray = new Array("33", "44", "55");
myArray = myArray.concat("3", "2", "1");
console.log(myArray);
// ["33", "44", "55", "3", "2", "1"]
var myArray = new Array('Red','Blue','Yellow');
var list = myArray.join(", ");
console.log(list);
// "Red, Blue, Yellow"
var myArray = new Array ("1", "2", "3");
myArray.reverse();
// transposes the array so that myArray = [ "3", "2", "1" ]
var myArray = new Array("A", "C", "B");
myArray.sort();
// sorts the array so that myArray = [ "A","B","c" ]
var a = ['a', 'b', 'a', 'b', 'a','c','a'];
console.log(a.indexOf('b')); // 1
// Now try again, starting from after the last match
console.log(a.indexOf('b', 2)); // 3
console.log(a.indexOf('1')); // -1, 'q' is not found
const a1 = [1,1,3];
const a2 = [...new Set(a1)]; // [1,3]
[1, 2, 3].map(x => x * 10).reduce((sum,x) => sum + x) // 60
[1, 2, 3].map(function(x, idx, arr){ return arr[0] + x + idx + this.salt}, {salt: 100}) // 102, 104, 106
// reduceRight is starting at the end and looping until the beginning of the array
["a","b","c"].reduce((sum,x) => sum + x) // abc
["a","b","c"].reduceRight((sum,x) => sum + x) // cba
[1,2,3,4,5].filter(x => x > 2) // 3,4,5
[1,2,3,4,5].find(x => x > 2) // 3
[1,2,3,4,5].some(x => x > 2) // true
[1,2,3,4,5].every(x => x > 2) // false
// ES10
[1,2,[3,4,[5,6]]].flat() // [1, 2, 3, 4, Array(2)]
[1,2,[3,4,[5,6]]].flat().flat() // [1, 2, 3, 4, 5, 6]
// ES10
[1,2,3].flatMap(x => [x,x]) // [1, 1, 2, 2, 3, 3]
// takes functions as parameters, each function takes x as a parameter
// await for the promise `y` and apply the next function (`f`)
// the result becomes the next `y`
const asyncPipe = (...fns) => x => (
fns.reduce(async (y, f) => f(await y), x)
)
const uploadFiles = asyncPipe(
readUser,
getFolderInfo,
haveWriteAccess,
uploadToFolder
)
uploadFiles({user, folder, files}) // a composited param `x` (merged params for all the functions)
.then(log)
// Compose functions from top to bottom:
const pipe = (...fns) => x => fns.reduce((y, f) => f(y), x);
// Sugar to kick off the pipeline with an initial value:
const sumT = (...fns) => pipe(...fns)(t(0));
sumT(
t(2),
t(4),
t(-1)
).valueOf(); // 5
Object.assign(destination, a, b)
/* or */
{...a, ...b}
const delegate = (a, b) => Object.assign(Object.create(a), b);
const d = objs.reduceRight(delegate, {});
var founders = new Map();
founders.set("facebook", "mark");
founders.set("google", "larry");
founders.size; // 2
founders.get("twitter"); // undefined
founders.has("yahoo"); // false
for (var [key, value] of founders) {
console.log(key + " founded by " + value);
}
// "facebook founded by mark"
// "google founded by larry"
var mySet = new Set();
mySet.add(1);
mySet.add("Howdy");
mySet.add("foo");
mySet.has(1); // true
mySet.delete("foo");
mySet.size; // 2
for (let item of mySet) console.log(item);
// 1
// "Howdy"
let input = [1, 2];
let [first, second] = input;
console.log(first); // outputs 1
console.log(second); // outputs 2
// swap variables
[first, second] = [second, first];
var [x, y, ...remaining] = [1, 2, 3, 4];
console.log(x, y, remaining); // 1, 2, [3,4]
// destructuring with ignore
var [x, , ...remaining] = [1, 2, 3, 4];
console.log(x, remaining); // 1, [3,4]
// object destructuring
var {w, x, ...remaining} = {w: 1, x: 2, y: 3, z: 4};
console.log(w, x, remaining); // 1, 2, {y:3, z:4}
// destructuring for array items
var csvFileLine = '1997,John Doe,US,[email protected],New York';
var { 2: country, 4: state } = csvFileLine.split(',');
// destructuring for function parameters
var numbers = [1,2,3];
Math.max(...numbers); //3
function doSomething({ foo = 'Hi', bar = 'Yo!', baz = 13 }) {
// ...
}
// make the parameters optional
function doSomething({ foo = 'Hi', bar = 'Yo!', baz = 13 } = {}) {
// ...
}
var list = ['Apple','Orange','Banana'];
for (let i in list){
console.log(i); // 0 1 2
}
for (let i of list){
console.log(i); // Apple Orange Banana
}
The in
operator can be used to check if a property name exists in an object:
'b' in [a:1, b:2] // true
1 in [a:1, b:2] // false
The in
operator, when used together with arrays, will check if an index exists:
'b' in ['a', 'b'] // false
1 in ['a', 'b'] // true
You can check for properties on built-in data types:
'length' in [] // true
'constructor' in Object // true
'a' in {a:1} // true
switch (true) {
case (tempInCelsius <= 0):
state = 'Solid';
break;
case (tempInCelsius > 0 && tempInCelsius < 100):
state = 'Liquid';
break;
default:
state = 'Gas';
}
var pattern = /test/flag;
var pattern = new RegExp("test", flag); /* alternatively */
-
i
: case-insensitive. -
g
: matches all the instances of the pattern as opposed to the default of local, which matches the first occurrence only. -
m
: allows matches across multiple lines.
> /orange/ig.test("Orange Juice") // true
/Toy/g.exec('A Toyota! Race fast, safe car! A Toyota!');
'A Toyota! Race fast, safe car! A Toyota!'.match(/Toy/g);
try {
var a = doesnotexist; // throws a runtime exception
} catch(e) {
console.log(e.message); // doesnotexist is not defined
} finally {
// will be always executed
}
A return
inside a finally
has the special ability to override a previous return
from the try
or catch
clause, but only if return
is explicitly called:
function foo() {
try {
return 42
} finally {
// no `return ..` here, so no override
} }
function bar() {
try {
return 42
} finally {
// override previous `return 42`
return
} }
function baz() {
try {
return 42
} finally {
// override previous `return 42`
return "Hello"
} }
foo() // 42
bar() // undefined
baz() // Hello
function willThrowException(){
throw new Error("Invalid State");
}
try {
...
} catch {
console.log('Something went wrong.');
}
let json = JSON.stringify({ name:"Tomas", surname:"Tulka"})
json // {"name":"Tomas","surname":"Tulka"}
let obj = JSON.parse(json)
// a direct object
var author = {
firstname : "Douglas",
lastname : "Crockford",
book : {
title:"JavaScript- The Good Parts",
pages:"172"
}
};
Object.keys(author); // [ 'firstname', 'lastname', 'book' ]
There is one default property for almost all objects, called a prototype.
function Person() {}
Person.prototype.cry = function() { console.log("Crying"); }
var bob = new Person()
bob.cry() // Crying
var a = {v: "my value"}
var b = Object.create(a)
console.log(b.v) // my value
a.v = "updated"
console.log(b.v) // updated
var anotherObject = { a: 2 }
var myObject = Object.create( anotherObject )
anotherObject.a // 2
myObject.a // 2
anotherObject.hasOwnProperty( "a" ) // true
myObject.hasOwnProperty( "a" ) // false
myObject.a++ // implicit shadowing!
anotherObject.a // 2
myObject.a // 3
myObject.hasOwnProperty( "a" ) // true
var Person = function(name) {
this.name = name;
};
var albert = new Person('Albert Einstein');
console.log(albert.name); // Albert Einstein
Functions themselves are not constructors. However, when you put the new
keyword in front of a normal function call, that
makes that function call a “constructor call.” In fact, new sort of hijacks any normal function and calls it in a fashion that constructs an object, in addition to whatever else it was going to do:
function NothingSpecial() {
console.log( "Don't mind me!" )
}
var a = new NothingSpecial()
// "Don't mind me!"
a // {}
function Child() {}
Child.prototype = new Person();
var aChild = new Child();
console.log(aChild instanceof Child); //true
console.log(aChild instanceof Person); //true
console.log(aChild instanceof Object); //true
var person = {
firstname: "Albert",
lastname: "Einstein",
get fullname() {
return this.firstname +" "+this.lastname;
},
set fullname(_name){
var words = _name.toString().split(' ');
this.firstname = words[0];
this.lastname = words[1];
}
};
person.fullname = "Issac Newton";
console.log(person.firstname); // "Issac"
console.log(person.lastname); // "Newton"
console.log(person.fullname); // "Issac Newton"
- Class declarations are not hoisted (you first need to declare your class and then access it) - in opposite of functions.
class Rectangle {
// Attributes have an implicit getter/setter.
constructor(height, width) {
this.height = height;
this.width = width;
}
// Getter
get area() {
return this.calcArea();
}
// Method
calcArea() {
return this.height * this.width;
}
// Static method
static calcDiagonal(h, w) {
return Math.sqrt(Math.pow(h,2) + Math.pow(w,2))
}
}
const square = new Rectangle(10, 10);
console.log(square.area); // 100
console.log(Rectangle.calcDiagonal(2,3)); // 3.605551275463989
class Human {
speak() { console.log('Ecce homo!'); }
}
class Physicist extends Human {
speak() {
super.speak();
console.log('E=m*c^2'); }
}
var albert = new Physicist();
albert.speak(); // Ecce homo!\nE=m*c^2
let obj = {
a: "foo",
b: 123,
c: {
d: "bar"
}
};
let { a, b, c: {d} } = obj;
a // 'foo'
b // 123
c // not defined
d // 'bar'
// Property renaming
let { a: newName1, b: newName2 } = obj;
The first argument is the target, and any other arguments passed are the sources, which will be processed in listed order. For each source, its enumerable and own (e.g., not “inherited”) keys, not symbols, are copied as if by plain =
assignment and the target object is returned:
var target = {}
var o1 = { a: 1 }, o2 = { b: 2 }
Object.assign( target, o1, o2 ) // { a: 1, b: 2 }
target // { a: 1, b: 2 }
A proxy is a special kind of object you create that “wraps" — or sits in front of — another normal object.
Example: pre-define all the properties/methods for an object, and have an error thrown if a non-existent property name is subsequently used:
var obj = { a: 1, foo () { console.log("a:", this.a) } }
var handlers = {
get(target,key,context) {
if (Reflect.has( target, key )) {
return Reflect.get(target, key, context)
} else {
throw "No such property/method!";
}
} }
var pobj = new Proxy( obj, handlers )
pobj.a // 3
pobj.foo() // a: 3
pobj.b // Error: No such property/method!
pobj.bar() // Error: No such property/method!
console.trace()
-
console.time()
&&console.timeEnd()
console.memory
console.count('STUFF I COUNT')
console.assert(false, 'Log me!')
console.clear()
console.table({name:"Tomas", age:33}, {name:"John", age:26},)
%s
= string, %i
= integer, %o
= object, %f
= float
console.log("Hello, %s. Your numer is %i.", "Tomas", 123)
// DON'T
function getRegisteredUsers (fields, include, fromDate, toDate) { /* implementation */ }
getRegisteredUsers(['firstName', 'lastName', 'email'], ['invitedUsers'], '2016-09-26', '2016-12-13')
// DO
function getRegisteredUsers ({ fields, include, fromDate, toDate }) { /* implementation */ }
getRegisteredUsers({
fields: ['firstName', 'lastName', 'email'],
include: ['invitedUsers'],
fromDate: '2016-09-26',
toDate: '2016-12-13'
})
// AVOID
asyncFunc1((err, result1) => {
asyncFunc2(result1, (err, result2) => {
asyncFunc3(result2, (err, result3) => {
console.lor(result3)
})
})
})
// PREFER
asyncFuncPromise1()
.then(asyncFuncPromise2)
.then(asyncFuncPromise3)
.then((result) => console.log(result))
.catch((err) => console.error(err))
- Jasmine: Behavior-driven testing (https://jasmine.github.io)
- Node.js: Server-side JavaScript runtime engine (https://nodejs.org)
- Express: Minimalist web framework for Node.js (https://expressjs.com)
- Underscore.js: Library for functional features and utilities (http://underscorejs.org)
- jQuery: Library for DOM traversal and manipulation (https://jquery.com)
- Backbone.js: MVC-framework for JavaScript applications (http://backbonejs.org)
- AngularJS: Framework for builing interactive single-page web applications (https://angularjs.org)
- React: Library for building user reactive interfaces (https://reactjs.org)
- Redux: State container for JavaScript apps (https://redux.js.org)
- CommonJS: Modularity framework (http://requirejs.org/docs/commonjs.html)
- Vue.js: Framework for building user interfaces (https://vuejs.org)
- Polymer: Library for building web applications using Web Components (https://www.polymer-project.org, https://www.webcomponents.org)
- Ved Antani: Mastering JavaScript
- Federico Kereki: Mastering JavaScript Functional Programming
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference
- Alternatives to Classes in JS: https://youtu.be/1AJsAPszZJ0
- https://blog.risingstack.com/javascript-clean-coding-best-practices-node-js-at-scale
- https://medium.freecodecamp.org/9-neat-javascript-tricks-e2742f2735c3
- https://davidwalsh.name/javascript-objects
- http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony
- Kyle Simpson: You don't know JS (series)
- https://medium.com/javascript-scene/a-functional-programmers-introduction-to-javascript-composing-software-d670d14ede30
- https://medium.com/javascript-scene/composable-datatypes-with-functions-aec72db3b093
- https://medium.com/javascript-scene/the-hidden-treasures-of-object-composition-60cd89480381
- https://medium.com/javascript-scene/javascript-monads-made-simple-7856be57bfe8
- https://www.nearform.com/blog/wormholes-in-javascript/
- https://medium.com/coinmonks/everything-you-wanted-to-know-about-package-lock-json-b81911aa8ab8
- https://flaviocopes.com/javascript-regular-expressions
- https://codeburst.io/javascript-null-vs-undefined-20f955215a2
- https://medium.com/appsflyer/10-tips-for-javascript-debugging-like-a-pro-with-console-7140027eb5f6
- Cheatsheet for JavaScript array methods: https://gist.github.com/rauschma/f7b96b8b7274f2e2d8dab899803346c3
- Tips for JavaScript: https://medium.com/@bretcameron/12-javascript-tricks-you-wont-find-in-most-tutorials-a9c9331f169d
- JavaScript Quiz: http://davidshariff.com/js-quiz
- Clean Code in JavaScript: https://github.com/ryanmcdermott/clean-code-javascript
- Async Patterns: https://jdxcode.com/posts/2020-01-19-async-javascript-patterns-for-2020/
- AST Explorer: https://astexplorer.net/
- Equality Coercion Table: https://dorey.github.io/JavaScript-Equality-Table/
- JavaScript Visualized Serie
- Can (a== 1 && a ==2 && a==3) ever evaluate to true?
- Designing very large JavaScript applications
- A lot of JS questions
- Write your own arbitrary precision javascript math library
- Unicode in JavaScript
- Invisible JavaScript Backdoor
- Emoji under the hood
- New features by ES versions
- JavaScript WTF