An event listener is added to a parent element instead of on its descendants. As child events bubbles up DOM the event is triggered. This allows less memory usage and having to handle events after removing or adding descendants.
When an event triggers on a DOM element, it will attempt to handle the event if there is a listener attached, then the event is bubbled up to its parent and the same thing happens. This bubbling occurs up the element's ancestors all the way to the document
.
- When using
new
to call a function is a new, empty object. - When using
apply
,call
orbind
it is the argument passed. - When called as method, it's the object instance that contains the function.
- When called as a free function (not the above conditions), it's the global object. (window in browsers)
- If multiple rules apply, the rule higher rule wins.
- In ES6 arrow functions, it's the surrounding scope at the moment of its creation.
Javascript objects have a prototype
property with a reference to a base or creator object. When a property of the object is requested, if not found in the object, it will look on it's prototype, in its protype's prototype and so on. This works more delegating than copying or classical inheritance.
apply
: executes a function passing a single array containing the arguments.call
: executes a function passing multiple arguments.bind
: creates a new function passing the first parameter asthis
and the next parameters as arguments.
Intended to deal with encapsulation and dependencies.
- Cannot import other modules
- no async loading
function EmployeeDetails() {
var name: "Mayank";
var age = 30;
var designation = "Developer",
var salary = 10000;
return {
name: name,
age: age,
designation: designation
}
}
var newEmployee = EmployeeDetails()
// This will result in "undefined" value
var userName = newEmployee.salary;
- Asynchronous (better startup times)
- Browser oriented
- Dependency management fully integrated.
- Verbose
// define(id?, dependencies?, factory);
define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {
exports.verb = function() {
return beta.verb();
//Or:
return require("beta").verb();
}
});
- Synchronous.
- Server oriented.
- Almost the same than Node Modules.
exports
object which contains what will be outputed. Bound tomodule.exports
.module.exports
is an special object that takesexports
and actually is exported.
function myModule() {
this.hello = function() {
return 'hello!';
}
this.goodbye = function() {
return 'goodbye!';
}
}
module.exports = myModule;
// USAGE
var myModule = require('myModule');
var myModuleInstance = new myModule();
myModuleInstance.hello(); // 'hello!'
myModuleInstance.goodbye(); // 'goodbye
- Synchronous and Asynchronous compatibility.
import
directive is not dynamic. Cannot be called in any place.
- for data privacy
- avoid collitions by not polluting the global namespace or scope.
- helps with code minification.
- reduce scope lookups (references are resolved faster).
- ES5
let
comes to solve the scope encapsulation problem too.
(function () {
var aName = "Barry";
})();
- undeclared: not declared with
var
,let
orconst
. Throws an error in strict mode. Checked withtry
/catch
. BAD! undefined
: declared but not assigned. Check with===
,typeof x === 'undefined'
orx === undefined
.null
: explicitely assigned. Represents no value. Check with===
operator.
-
A closure is the combination of a function and the lexical environment within which that function was declared.
-
Functions that have access to the outer (enclosing) function's variables—scope chain even after the outer function has returned.
-
Used in the Module Pattern, emulating private methods.
Describes how a parser resolves variable names when functions are nested. The word "lexical" refers to the fact that lexical scoping uses the location where a variable is declared within the source code to determine where that variable is available. Nested functions have access to variables declared in their outer scope.
This environment consists of any local variables that were in-scope at the time the closure was created.
The main difference between .forEach()
and .map()
is that .map
returns a new array. If you need the result, but do not wish to mutate the original array, .map
is the clear choice. If you simply need to iterate over an array, forEach
is a fine choice.
Functions dynamically declared at runtime. They aren’t given a name in the same way as normal functions.
- Used in IIFE's
- Function callbacks (e.g.
setTimeout()
) - Arguments for functions / functional programming
Native objects are objects that are part of the JavaScript language defined by the ECMAScript specification, such as String, Math, RegExp, Object, Function.
Host objects are provided by the runtime environment (browser or Node), such as window
, XMLHTTPRequest
, etc.
Is a function that: takes one or more functions as arguments (i.e. procedural parameters), returns a function as its result.
Ajax (asynchronous JavaScript and XML) is a set of web development techniques using many web technologies on the client side to create asynchronous web applications.
Is a method commonly used to bypass the cross-domain policies in web browsers because Ajax requests from the current page to a cross-origin domain is not allowed. Works by making a request to a cross-origin domain via a <script>
tag and usually with a callback query parameter, for example: https://example.com?callback=printData
. The server will then wrap the data within a function called printData
and return it to the client.
Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional HTTP headers to tell a browser to let a web application running at one origin (domain) have permission to access selected resources from a server at a different origin.Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional HTTP headers to tell a browser to let a web application running at one origin (domain) have permission to access selected resources from a server at a different origin.
Hoisting is a term used to explain the behavior of variable declarations in your code. Variables declared or initialized with the var
keyword will have their declaration "moved" up to the top of the current scope, which we refer to as hoisting. However, only the declaration is hoisted, the assignment (if there is one), will stay where it is. Declarations with let
and const
are not hoisted.
Function declarations have the body hoisted while the function expressions (written in the form of variable declarations) only has the variable declaration hoisted.
Phillip Roberts talk explaining What the heck is the Event Loop.
TBD
- var: allows the variable to be reasigned and re-declared. Declaration is made at function scope and could cause unintentional modifications.
- let: doesn't allow to be reasigned (you cannot do
let
more than once). Declaration is made at block scope. Allows reasignment. - const: variables declared with const cannot be redeclared nor re-declared. Although, in objects, properties can be changed. Declaration is made at block scope.
- Implicit return: you need to wrap the returned object in parenthesis:
you cannot just do:
const myObject = otherObject.map(item, i) => ({ name: item, username: item + 'username', index: i }))
const myObject = otherObject.map(item, i) => { name: item, username: item + 'username', index: i })
- Convenient return (a boolean) evaluating a condition:
const older = ages.filter(age => age >= 60)
- value of
this
is not automatically bouded to functionconst box = document.querySelector('.box') box.addEventListener('click', () => { console.log(this) }) // will output "window" instead of box
- Template strings (TS) are declared using backsticks:
const name = 'Template string' const template = `This is a ${name} and it's awesome! No more contatenation :)`
- Expressions can be used inside a TS:
const dogAge = 7 const template = `the dog age is ${dogAge * 7}`
- TS supports multiline content:
const template = ` <div> <h1>My headline</h1> </div> `
- Looping inside a TS is possible:
const dogs = [ { name: 'Snickers', age: 2 }, { name: 'Hugo', age: 8 }, { name: 'Sunny', age: 1 } ] const markup = ` <ul class="dogs"> ${dogs.map(dog => ` <li>${dog.name} is ${dog.age * 7}</li> `).join('')} </ul> `
- Tagged template literals:
function highlight(strings, ...values) { let str = ''; strings.forEach((string, i) => { str += `${string} <span contenteditable class="hl">${values[i] || ''}</span>`; }); return str; } const name = 'Snickers'; const age = 100; const sentence = highlight`My dog's name is ${name} and he is ${age} years old`;
All these expressions returns true
:
'Contact, 1997'.startsWith('Con')
'Contact, 1997'.startsWith('19', 8)
'Contact, 1997'.endsWith('97')
'Contact, 1997'.endsWith('act', 7)
'This is a sentence.'.includes('is')
'🚀'.repeat(3) === '🚀🚀🚀'
The Promise
object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
- Callbacks added with then() will never be invoked before the completion of the current run of the JavaScript event loop.
- These callbacks will be invoked even if they were added after the success or failure of the asynchronous operation that the promise represents.
- Multiple callbacks may be added by calling then() several times. They will be invoked one after another, in the order in which they were inserted.
function getImage(file) {
return new Promise((resolve, reject) => {
try {
const data = readFile(file)
resolve(data)
} catch (err) {
reject(new Error(err))
}
})
}
getImage(file)
.then(image => console.log(image))
.catch(err => console.log(err))
.finally(() => console.log("All done!"))
// Promise chain example
doSomething()
.then(function(result) {
return doSomethingElse(result);
})
.then(newResult => doThirdThing(newResult))
.then(() => doFourthThing())
.catch(error => console.error(error));
The async
and await
keywords enable asynchronous, promise-based behavior to be written in a cleaner style, avoiding the need to explicitly configure promise chains.
// Rewriting a Promise chain with an async function (not the previous example)
async function getProcessedData(url) {
let v
try {
v = await downloadData(url)
} catch(e) {
v = await downloadFallbackData(url)
}
return processDataInWorker(v)
}
The Promise.all()
method takes an iterable of promises as an input, and returns a single Promise that resolves to an array of the results of the input promises.
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
});
// expected output: Array [3, 42, "foo"]
The Promise.race()
method returns a promise that fulfills or rejects as soon as one of the promises in an iterable fulfills or rejects, with the value or reason from that promise.
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});
Promise.race([promise1, promise2]).then((value) => {
console.log(value);
// Both resolve, but promise2 is faster
});
// expected output: "two"
- An object can be made "somehow" inmutable by using Object.freeze(). However it is not necesarilly a constant.
Objects are simple name / value collections. They are similar to hash tables (C, C++), hash maps (Java) or associative arrays (PHP). name is a string and its value any other type (including objects).
- Literal object declaration (
var obj = {}
) is preferred.
The following items evaluates as false
: false
, 0
, ""
, NaN
, null
and undefined
. Any other value evaluates as true
.
- Phases of Events: Capturing and Bubbling
- Complete EventLoop
- Types of async handling: async/await, callbacks, promises, generators.
- What happens when you type in a URL in an address bar in a browser? -> https://www.knowbe4.com/hubfs/How-The-Web-Works.jfif
- Promises: how they work / excercises
- Heap?
- Big O notation
- Add info for UMD Modules
- Enhance info for Native/ES2015 modules: https://www.freecodecamp.org/news/javascript-modules-a-beginner-s-guide-783f7d7a5fcc/