I'm relearning JS by reading MDN's JS guide.
I’m doing so as a try to understand the weird stuff in JS cause there must be an explanation right?
This is more like personal notes but maybe it would be helpful to anyone else:)
💡 This may or may not be updated everyday
Grammar and types
-
There's a third type of comments "Hashbang" comments
#!/usr/bin/env node
it specifies the path to a specific JavaScript interpreter that you want to use to execute the script
It acts the same as single-line comments
//
butit must be at the beginning of a file
it can't have any whitespace before
-
you can use letters like å, ü (I mean they never said you can't but still I was like Woah when it run without errors)
it's because JS uses the Unicode character set
-
let
vars are hoisted but not initialized unlikevar
they are considered to be in a "temporal dead zone"
console.log('The value of b is ' + b); // The value of b is undefined var b; console.log('The value of y is ' + y); // Uncaught ReferenceError: y is not defined let y;
The
undefined
value converts toNaN
when used in numeric contextsnull value behaves as 0 in numeric contexts and as false in boolean contexts
-
function expression is not hoisted
baz(); // TypeError: baz is not a function console.log(baz) // undefined var baz = function() { console.log('bar2'); };
-
Only with the + operator JavaScript converts numeric values to strings
In case of + and the expression involving strings both sides are converted to string and concatenation is performed
in case of any other operation it tries to convert both sides to numbers if it's okay then the operation is performed if not
NaN
is returned
x = 'The answer is ' + 42 // "The answer is 42" x = 'The answer is ' - 42 // NaN x = '45' - '3' // 42 x = '45' + '3' // 453
-
you can create functions and dynamic named properties inside objects
var obj = { toString() { // Super calls return 'd ' + super.toString(); }, // Computed (dynamic) property names [ 'prop_' + (() => 42)() ]: 42 };
Loops and iteration
- Starting from es6 JS has block scope (for, if, while)
-
JS labels used with
break
andcontinue
to take effect on any block in the hierarchyfor example if you have a loop and another inside of it you can use the label to break from the loop inside the the second loop
for (let i = 0; i < 5; i++) { console.log("i", i); for (let j = 5; j > 0; j--) { if (i === j) break; // breaks only from the second for and continues the loop } } loop1: for (let i = 0; i < 5; i++) { console.log("i", i); for (let j = 5; j > 0; j--) { if (i === j) break loop1; // breaks from both loops } }
Can you use labeled statement to break from
forEach
loops? No by experiment!for ... of → iterate over iterable objects values (Map, Set, Array)
for ... in → iterate over enumerable property keys of an object
Fun Fun Functions
- function hoisting only works with function declarations not with function expression or arrow function
- A function can call itself using
arguments.callee()
nice to know but don't use it -
When you have a function with an inner function that inner function forms closure which means it can access all the variables defined in the outer function
The inner function has a reference to the args in the outer function and the reference is preserved until the inner function is no longer accessible
The
arguments
object it's an array-like not an array it only haslength
property and numbered indexan arrow function doesn't have its own
this
,super
, orarguments
use
Number.isNaN()
instead ofisNaN
causeisNaN
is weird and you know it-
the only difference between
encodeURI
andencodeURIComponent
isencodeURI
ignores protocol and domain nameencodeURIComponent
encodes everything the whole string
Expressions and operators
- + true returns 1
- >> shifts bits to the right
- >>> shifts bits to the right and adds zeros at the left instead of the shifted bits
- In bitwise operations the operands are converted to 32bits binary representation
- && and || returns one of the expression values
- Use nullish operator ?? Instead of || in case of 0 and ‘’ are valid values
typeof null // returns object!!!!!!
-
void
operator evaluates an expression then returns undefinedIt can be used with functions that don't intend to return any values
function x() { const x = 2; console.log("X", x); return x; } const revealed = () => x(); console.log(revealed()); // 2 const hidden = () => void x(); console.log(hidden()); // undefined
In operator: it’s like
hasOwnProperty
in objects
Numbers & Dates
- Use BigInt to represent very large numbers
- Math can’t be used with BigInt values
- you can't mix and match BigInt and Number values in the same operation
- Number like 0777 (with leading 0 and numbers are less than 8)would be considered an octal in non strict mode
- To write an octal number in ES5 add the prefix 0o777
- Math.toPrecision ??
- Creating Date without the new keyword returns only a date string not an object
- Date.parse() to convert a date string to date object
Text formatting
-
When using a string literal
let str = “str”
JS converts it to a temporary String object apply any methods then returns the result discarding the object
-
Strings are immutable array-like object so you can't just assign a value to a certain index
let str = “str”; str[2] = “y”; // won't do anything
str.repeat(42) just repeats a string
charCodeStr.normalize() cause a string can be represented in different ways using char code normalize makes all the presentations are equal
Intl.collator(sort type) used for sorting and comparing strings for internationalization like handling different sort types in German
Regular Expressions
- Use literal regular expression if the pattern is a constant for better performance
Indexed collections
-
Looping through a list of nodes? use this it’s more convenient
You wont need to check the length
You make sure the node is assigned to the var
let divs = document.getElementsByTagName('div') for (let i = 0, div; div = divs[i]; i++) { /* Process div in some way */ }
it is not advisable to iterate through JavaScript arrays using for...in loops, because normal elements and all enumerable properties will be listed.
-
How to call array methods on array-like objects
Using prototype.call
function printArguments() { Array.prototype.forEach.call(arguments, function(item) { console.log(item); }); }
Typed arrays are array-like objects with a mechanism for accessing raw binary data
-
Typed arrays architecture is divided into buffer and view
Buffer is a chunk of data that has no mechanism to access like an ArrayBuffer
View is your way to access the buffer data it provides a context with data type (that is why it’s typed array it has a type!), starting offset and number of elements like a DataView
There are different typed array views and they have descriptive names like
int8Arrays
which means the view size is 8 bits/1byteThere is one special typed array view,
Uint8ClampedArray
, which clamps the values between 0 and 255. This is useful for Canvas data processing
Keyed Collections
- Normal objects are not iterable
- You can get the size of a Map easily, while you have to manually keep track of size for an Object
- The iteration of maps is in insertion order of the elements. The order doesn’t matter in objects
- Use maps if there is a need to store primitive values as keys because object treats each key as a string whether it's a number value, boolean value or any other primitive value
- WeakMap keys are only objects and they are weakly held meaning that they are a target of garbage collection (GC) if there is no other reference to the object anymore
- WeakMap keys are not enumerable you can’t have access to the list of keys
- WeakMaps are usually used for privacy check an example
- You can convert from set to array using spreed operator
- WeakSets are collections of objects only
- WeakSets are not enumerable
Working with objects (to reread)
- Object.create() method. This method can be very useful, because it allows you to choose the prototype object for the object you want to create without having to define a constructor function. >> inheritance
-
You access forms in a document using document.forms
document.forms[1] // returns first document appears in the document
document.forms[‘my-form’] // returns the form with name property equals my-form
-
Getters and setters can be added to an object at any time after creation using the Object.defineProperties method
var o = { a: 0 }; Object.defineProperties(o, { 'b': { get: function() { return this.a + 1; } }, 'c': { set: function(x) { this.a = x / 2; } } }); o.c = 10; // Runs the setter, which assigns 10 / 2 (5) to the 'a' property console.log(o.b); // Runs the getter, which yields a + 1 or 6
Details of the object model (to reread)
-
Creating a new object from a function you can omit the parenthesis if there're no params
const jane = new Engineer;
-
Method delegation can preserve memory resources because you only need one copy of each method to be shared by all instances
function Greeter(name) { this.name = name || "John Doe"; } Greeter.prototype.hello = function hello() { return "Hello, my name is " + this.name; }; const george = new Greeter("George"); const jack = new Greeter("jack"); console.log(george.hello === jack.hello); // true (means they have the same reference)
In JavaScript, any function can create new objects. When it’s not a constructor function, it’s called a factory function like
Object.create()
Using Promises
- a promise is a returned object to which you attach callbacks, instead of passing callbacks into a function.
- It's possible to chain after a failure, i.e. a
catch
, which is useful to accomplish new actions even after an action failed in the chain Like a finally in a try catch - Promises rejection events are of type
[PromiseRejectionEvent](https://developer.mozilla.org/en-US/docs/Web/API/PromiseRejectionEvent)
has as members a[promise](https://developer.mozilla.org/en-US/docs/Web/API/PromiseRejectionEvent/promise)
property indicating the promise that was rejected, and a[reason](https://developer.mozilla.org/en-US/docs/Web/API/PromiseRejectionEvent/reason)
property that provides the reason given for the promise to be rejected - All rejections are raised to global scope (either window or worker) And they come in two types
-
rejectionhandled
Sent when a promise is rejected, after that rejection has been handled by the executor'sreject
function. -
unhandledrejection
Sent when a promise is rejected but there is no rejection handler available.
-
-
Promisifying
setTimeout
const wait = ms => new Promise(resolve => setTimeout(resolve, ms)); wait(10*1000).then(() => saySomething("10 seconds")).catch(failureCallback);
You can use
Promise.resolve()
andPromise.reject()
to manually create an already resolved or rejected promise-
Promise.all reusable compose function
const applyAsync = (acc,val) => acc.then(val); const composeAsync = (...funcs) => x => funcs.reduce(applyAsync, Promise.resolve(x));
Top comments (0)