JavaScript Flashcards
What is Hoisting?
Hoisting is JavaScript’s default behavior of moving declarations to the top.
Variables defined with let and const are hoisted to the top of the block, but not initialized.
Functions:
Function declarations are hoisted and can be invoked before declaration:
hoisted(); // Output: “This function has been hoisted.”
function hoisted() {
console.log(‘This function has been hoisted.’);
};
Function expressions are not hoisted:
expression(); //Output: “TypeError: expression is not a function
var expression = function() {
console.log(‘Will this work?’);
};
What is Strict Mode?
Strict mode removes the usage of variables before they are declared.
Running our code in strict mode:
Eliminates some silent JavaScript errors by changing them to explicit throw errors which will be spit out by the interpreter.
Fixes mistakes that make it difficult for JavaScript engines to perform optimisations.
Prohibits some syntax likely to be defined in future versions of JavaScript.
What is the difference between let, const, and var?
Variables declared using the var keyword are scoped to the function in which they are created, or if created outside of any function, to the global object. let and const are block scoped, meaning they are only accessible within the nearest set of curly braces (function, if-else block, or for-loop).
if (true) {
var bar = ‘bar’;
let baz = ‘baz’;
const qux = ‘qux’;
}
// var declared variables are accessible anywhere in the function scope.
console.log(bar); // bar
// let and const defined variables are not accessible outside of the block they were defined in.
console.log(baz); // ReferenceError: baz is not defined
console.log(qux); // ReferenceError: qux is not defined
Variables declared with let and const remain uninitialised at the beginning of execution while variables declared with var are initialised with a value of undefined.
What is the difference between ==
and ===
?
== is the abstract equality operator while === is the strict equality operator. The == operator will compare for equality after doing any necessary type conversions. The === operator will not do type conversion, so if two values are not the same type === will simply return false.
1 == ‘1’; // true
1 == [1]; // true
1 == true; // true
0 == ‘’; // true
0 == ‘0’; // true
0 == false; // true
What’s the difference between a variable that is: null
, undefined
or undeclared?
Undeclared variables are created when you assign a value to an identifier that is not previously created using var, let or const.
Ex:
function foo() {
x = 1; // Throws a ReferenceError in strict mode
}
A variable that is undefined is a variable that has been declared, but not assigned a value.
Ex:
var foo;
console.log(foo); // undefined
A variable that is null will have been explicitly assigned to the null value.
What’s the difference between .call
and .apply
?
Both .call and .apply are used to invoke functions and the first parameter will be used as the value of this within the function. However, .call takes in comma-separated arguments as the next arguments while .apply takes in an array of arguments as the next argument. An easy way to remember this is C for call and comma-separated and A for apply and an array of arguments.
function add(a, b) {
return a + b;
}
console.log(add.call(null, 1, 2)); // 3
console.log(add.apply(null, [1, 2])); // 3
Can you offer a use case for the new arrow => function syntax?
One obvious benefit of arrow functions is to simplify the syntax needed to create functions, without a need for the function keyword.
The this within arrow functions is also bound to the enclosing scope which is different compared to regular functions where the this is determined by the object calling it.
Lexically-scoped this is useful when invoking callbacks especially in React components.
Arrow functions always bind to the global object.
Explain function.prototype.bind()
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
bind() is most useful for binding the value of this in methods of classes that you want to pass into other functions. This was frequently done in React class component methods which were not defined using arrow functions.
const john = {
age: 42,
getAge: function () {
return this.age;
},
};
console.log(john.getAge()); // 42
const unboundGetAge = john.getAge;
console.log(unboundGetAge()); // undefined
const boundGetAge = john.getAge.bind(john);
console.log(boundGetAge());
Explain the difference between synchronous and asynchronous functions
Synchronous functions are blocking while asynchronous functions are not. In synchronous functions, statements complete before the next statement is run. In this case, the program is evaluated exactly in order of the statements and execution of the program is paused if one of the statements take a very long time.
Asynchronous functions usually accept a callback as a parameter and execution continue on the next line immediately after the asynchronous function is invoked. The callback is only invoked when the asynchronous operation is complete and the call stack is empty. Heavy duty operations such as loading data from a web server or querying a database should be done asynchronously so that the main thread can continue executing other operations instead of blocking until that long operation to complete (in the case of browsers, the UI will freeze).
What is a closure, and how/why would you use one?
A closure is the combination of a function and the lexical environment within which that function was declared. 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. Closures are functions that have access to the outer (enclosing) function’s variables—scope chain even after the outer function has returned.
Why would you use one?
Data privacy / emulating private methods with closures. Commonly used in the module pattern.
Partial applications or currying.
What is the event loop?
The event loop is a single-threaded loop that monitors the call stack and checks if there is any work to be done in the task queue. If the call stack is empty and there are callback functions in the task queue, a function is dequeued and pushed onto the call stack to be executed.
What’s a typical use case for anonymous functions?
They can be used in IIFEs to encapsulate some code within a local scope so that variables declared in it do not leak to the global scope.
As a callback that is used once and does not need to be used anywhere else. The code will seem more self-contained and readable when handlers are defined right inside the code calling them, rather than having to search elsewhere to find the function body.
Can you give an example of a curry function and why this syntax offers an advantage?
Used in functional programming.
Makes it easier to read and compose.
Currying is a pattern where a function with more than one parameter is broken into multiple functions that, when called in series, will accumulate all of the required parameters one at a time.
Explain how this
works in JavaScript
this = the context of a function invocation
this is the global object in a function invocation.
this is undefined in a function invocation in strict mode
this is the object that owns the method in a method invocation
The context of the inner function (except arrow function) depends only on its own invocation type, but not on the outer function’s context.
If the function is an ES2015 arrow function, it ignores all the rules above and receives the this value of its surrounding scope at the time it is created.
This = the object executing the function.
If the new keyword is used when calling the function, this inside the function is a brand new object.
If apply, call, or bind are used to call/create a function, this inside the function is the object that is passed in as the argument.
If a function is called as a method, such as obj.method() — this is the object that the function is a property of.
If a function is invoked as a free function invocation, meaning it was invoked without any of the conditions present above, this is the global object. In a browser, it is the window object. If in strict mode (‘use strict’), this will be undefined instead of the global object.
If multiple of the above rules apply, the rule that is higher wins and will set the this value.
What is currying?
It’s a process in functional programming in which you can transform a function with multiple arguments into a sequence of nesting functions. It returns a new function that expects the next argument inline.
instead of a function taking all arguments at one time, it takes the first one and returns a new function, which takes the second one and returns a new function, which takes the third one, and so on, until all arguments have been fulfilled.
Curried functions are constructed by chaining closures and by defining and immediately returning their inner functions simultaneously.
ex.
function sum(a) {
return (b) => {
return (c) => {
return a + b + c
}
}
}
const sum1 = sum(1);
const sum2 = sum1(2);
const result = sum2(3);
console.log(result); // 6