Basic JavaScript Questions

What is the difference between == and ===?

The usual answer would be one compares only the values while the other also compares the type. In this case, follow up question would be: Why null == undefined is true? As you can guess their values will never be equal.

A good answer is that == runs the loose equality check while === also compares the types. The loose equality check looks at the type on both sides and based on the types it decides what to do. The specifications states that if both sides of the comparison are null and undefined just return true.

So, it may just return true like in the case of null with undefined or it may try to convert one or the other side to the same type and compare their values depending on what is specified for a certain scenario.

What are closures and lexical scope?

A closure is when a function is able to remember and access its lexical scope even when that function is executed outside of that scope. A good example for closures is currying, a common accepted answer is also responding that an inner function returned by an outer function has access to its outer functions variables even after the outer function was called. Lexical scope is the scope model used by JavaScript which compared to dynamic scoping enables a lot of cool features. If someone also explains lexing time and goes into hoisting it is a big bonus.

What is data mutation and how to prevent it?

This is a bit tricky question as there are multiple correct answers and approaches. What we look for is understanding that arrays and objects can be passed around and since they are references, we are changing the original array or object. This leads to side effects and often to unwanted behaviour. The preferred way is never to mutate objects or arrays and when modifying, always create and return a new copy. We can take advantage of the spread operator, object.assign or libraries like ImmutableJS. Mentioning array.slice vs splice is a plus.

What is hoisting?

A common answer is: hoisting is a mechanism which moves all declarations to the top of the execution scope. A good answer is understanding that JavaScript compiles your code before execution. When the compiler enters an execution context, it will start lexing (splitting your code) and analysing the code while creating a list out of the declarations it finds. Each time the compiler encounters a declaration, it will create a binding to it and each time it encounters an assignment or evaluation it will ask the current scope for the binding, if it can’t find the binding, it will go up until it reaches the global scope. If you have strict mode on, you will get an error and if you use the good old es5 it will create a new binding for you. This is why, you are able to assign to a variable which wasn’t declared before. Anyway, after running through some steps, it will generate some compiled code which can be then executed :).

Explain inheritance in JavaScript.

JavaScript is a prototype based language and uses prototypal inheritance instead of the more common class inheritance, even though in ES6+ we use classes, they are just a syntactical sugar and they are still based on prototypes.

Prototypal inheritance is based on the prototype chain, in a simple example every object, objects instance, has a prototype. We can access it for instance trough the __proto__ property. This basically returns the objects parent. This way you can climb up the prototypal chain until you reach the top-level parent (object in this case) where the prototype is set to null. The advantage of the chain is, that if we call a property of an object, if it can’t be found on the object, JavaScript will automatically look for the property on the prototype, if it can’t find it on the prototype. It will look at the prototype of the prototype and so on until it reaches the top level and errors out.

What do you understand under asynchronous code in JS?

Synchronous code is code which is executed step by step, if we have a long running task we need to wait until it finishes executing before moving further and this basically blocks all other tasks if we don’t have multithreading. In case of a 5s long AJAX call, we would block the browser for 5 seconds unable to do anything. This is solved by asynchronous code where tasks can be executed in a non-blocking way. This is ensured by the event loop and uses the call stack and callback queue to provide asynchronous behaviour. In simple terms, we can register asynchronous tasks with the event loop to be executed in the future. JavaScript provides a few ways to achieve asynchronous code: via promises, async/await or generators.