Interview Questions 3 Flashcards
What are the pros of immutability?
Easier change detection - Object equality can be determined in a performant and easy manner through referential equality. This is useful for comparing object differences in React and Redux.
Programs with immutable objects are less complicated to think about, since you don’t need to worry about how an object may evolve over time.
Defensive copies are no longer necessary when immutable objects are returning from or passed to functions, since there is no possibility an immutable object will be modified by it.
Easy sharing via references - One copy of an object is just as good as another, so you can cache objects or reuse the same object multiple times.
Thread-safe - Immutable objects can be safely used between threads in a multi-threaded environment since there is no risk of them being modified in other concurrently running threads.
Using libraries like ImmutableJS, objects are modified using structural sharing and less memory is needed for having multiple objects with similar structures.
What are the cons of immutability?
Cons
Naive implementations of immutable data structures and its operations can result in extremely poor performance because new objects are created each time. It is recommended to use libraries for efficient immutable data structures and operations that leverage on structural sharing.
Allocation (and deallocation) of many small objects rather than modifying existing ones can cause a performance impact. The complexity of either the allocator or the garbage collector usually depends on the number of objects on the heap.
Cyclic data structures such as graphs are difficult to build. If you have two objects which can’t be modified after initialization, how can you get them to point to each other?
How can you achieve immutability in your own code?
The alternative is to use const declarations combined with the techniques mentioned above for creation. For “mutating” objects, use the spread operator, Object.assign, Array.concat(), etc., to create new objects instead of mutate the original object.
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 event loop? What is the difference between call stack and task queue?
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.
If you haven’t already checked out Philip Robert’s talk on the Event Loop, you should. It is one of the most viewed videos on JavaScript.
Explain the differences on the usage of foo between function foo() {} and var foo = function() {}
The former is a function declaration while the latter is a function expression. The key difference is that function declarations have its body hoisted but the bodies of function expressions are not (they have the same hoisting behavior as variables). For more explanation on hoisting, refer to the question above on hoisting. If you try to invoke a function expression before it is defined, you will get an Uncaught TypeError: XXX is not a function error.
Function Declaration
foo(); // ‘FOOOOO’
function foo() {
console.log(‘FOOOOO’);
}
Function Expression
foo(); // Uncaught TypeError: foo is not a function
var foo = function () {
console.log(‘FOOOOO’);
};
What are the differences between variables created using let, var or const?
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).
What are the differences between ES6 class and ES5 function constructors?
For simple constructors, they look pretty similar.
The main difference in the constructor comes when using inheritance. If we want to create a Student class that subclasses Person and add a studentId field, this is what we have to do in addition to the above.
// ES5 Function Constructor
function Student(name, studentId) {
// Call constructor of superclass to initialize superclass-derived members.
Person.call(this, name);
// Initialize subclass’s own members.
this.studentId = studentId;
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
// ES6 Class
class Student extends Person {
constructor(name, studentId) {
super(name);
this.studentId = studentId;
}
}
It’s much more verbose to use inheritance in ES5 and the ES6 version is easier to understand and remember.
Can you offer a use case for the new arrow => function syntax? How does this new syntax differ from other functions?
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.
What advantage is there for using the arrow syntax for a method in a constructor?
The main advantage of using an arrow function as a method inside a constructor is that the value of this gets set at the time of the function creation and can’t change after that.
So, when the constructor is used to create a new object, this will always refer to that object. For example, let’s say we have a Person constructor that takes a first name as an argument has two methods to console.log that name, one as a regular function and one as an arrow function:
const Person = function (firstName) {
this.firstName = firstName;
this.sayName1 = function () {
console.log(this.firstName);
};
this.sayName2 = () => {
console.log(this.firstName);
};
};
const john = new Person(‘John’);
const dave = new Person(‘Dave’);
john.sayName1(); // John
john.sayName2(); // John
// The regular function can have its ‘this’ value changed, but the arrow function cannot
john.sayName1.call(dave); // Dave (because “this” is now the dave object)
john.sayName2.call(dave); // John
john.sayName1.apply(dave); // Dave (because ‘this’ is now the dave object)
john.sayName2.apply(dave); // John
john.sayName1.bind(dave)(); // Dave (because ‘this’ is now the dave object)
john.sayName2.bind(dave)(); // John
var sayNameFromWindow1 = john.sayName1;
sayNameFromWindow1(); // undefined (because ‘this’ is now the window object)
var sayNameFromWindow2 = john.sayName2;
sayNameFromWindow2(); // John
The main takeaway here is that this can be changed for a normal function, but the context always stays the same for an arrow function. So even if you are passing around your arrow function to different parts of your application, you wouldn’t have to worry about the context changing.
This can be particularly helpful in React class components. If you define a class method for something such as a click handler using a normal function, and then you pass that click handler down into a child component as a prop, you will need to also bind this in the constructor of the parent component. If you instead use an arrow function, there is no need to also bind “this”, as the method will automatically get its “this” value from its enclosing lexical context.
What is the definition of a higher-order function?
A higher-order function is any function that takes one or more functions as arguments, which it uses to operate on some data, and/or returns a function as a result. Higher-order functions are meant to abstract some operation that is performed repeatedly.
The classic example of this is map, which takes an array and a function as arguments. map then uses this function to transform each item in the array, returning a new array with the transformed data.
Other popular examples in JavaScript are forEach, filter, and reduce. A higher-order function doesn’t just need to be manipulating arrays as there are many use cases for returning a function from another function. Function.prototype.bind is one such example in JavaScript.
Can you give an example for destructuring an object or an array?
Destructuring is an expression available in ES6 which enables a succinct and convenient way to extract values of Objects or Arrays and place them into distinct variables.
Array destructuring
// Variable assignment.
const foo = [‘one’, ‘two’, ‘three’];
const [one, two, three] = foo;
console.log(one); // “one”
console.log(two); // “two”
console.log(three); // “three”
// Swapping variables
let a = 1;
let b = 3;
[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1
Object destructuring
// Variable assignment.
const o = {p: 42, q: true};
const {p, q} = o;
console.log(p); // 42
console.log(q); // true
Can you give an example of a curry function and why this syntax offers an advantage?
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. This technique can be useful for making code written in a functional style easier to read and compose. It’s important to note that for a function to be curried, it needs to start out as one function, then broken out into a sequence of functions that each accepts one parameter.
function curry(fn) {
if (fn.length === 0) {
return fn;
}
function _curried(depth, args) {
return function (newArgument) {
if (depth - 1 === 0) {
return fn(…args, newArgument);
}
return _curried(depth - 1, […args, newArgument]);
};
}
return _curried(fn.length, []);
}
function add(a, b) {
return a + b;
}
var curriedAdd = curry(add);
var addFive = curriedAdd(5);
var result = [0, 1, 2, 3, 4, 5].map(addFive);
What are the benefits of using spread syntax and how is it different from rest syntax?
ES6’s spread syntax is very useful when coding in a functional paradigm as we can easily create copies of arrays or objects without resorting to Object.create, slice, or a library function. This language feature is used often in Redux and RxJS projects.
function putDookieInAnyArray(arr) {
return […arr, ‘dookie’];
}
const result = putDookieInAnyArray([‘I’, ‘really’, “don’t”, ‘like’]); // [“I”, “really”, “don’t”, “like”, “dookie”]
const person = {
name: ‘Todd’,
age: 29,
};
const copyOfTodd = {…person};
ES6’s rest syntax offers a shorthand for including an arbitrary number of arguments to be passed to a function. It is like an inverse of the spread syntax, taking data and stuffing it into an array rather than unpacking an array of data, and it works in function arguments, as well as in array and object destructuring assignments.
How can you share code between files?
This depends on the JavaScript environment.
On the client (browser environment), as long as the variables/functions are declared in the global scope (window), all scripts can refer to them. Alternatively, adopt the Asynchronous Module Definition (AMD) via RequireJS for a more modular approach.
On the server (Node.js), the common way has been to use CommonJS. Each file is treated as a module and it can export variables and functions by attaching them to the module.exports object.
ES2015 defines a module syntax which aims to replace both AMD and CommonJS. This will eventually be supported in both browser and Node environments.