Javascript
Source: https://medium.com/javascript-scene/10-interview-questions-every-javascript-developer-should-know-6fa6bdf5ad95
Key features
Interpreted language
No multithreading or multiprocess capabilities
Case-sensitive
Hoisting
Variables declared or initialized with the var
keyword will have their declaration "moved" up to the top of the current scope.
null vs undefined
Two distinct values for nothing: null and undefined.
undefined
Means: value of the variable is not defined.
Global variable undefined
whose value is "undefined"
typeof undefined
is also "undefined"
undefined is not a constant or a keyword. undefined is a type with exactly one value: undefined.
Assigning a new value to it does not change the value of the type undefined.
8 Ways to get Undefined:
A declared variable without assigning any value to it.
Implicit returns of functions due to missing return statements.
return statements that do not explicitly return anything.
Lookups of non-existent properties in an object.
Function parameters that have not passed.
Anything that has been set to the value of undefined.
Any expression in the form of void(expression)
The value of the global variable
undefined
null
Means empty or non-existent value. Used by programmers to indicate “no value”.
Primitive value. Not an object. You can assign null to any variable.
Sometimes people wrongly assume that it is an object, because typeof null returns "object".
undefined
vs not defined
undefined
vs not defined
If you try to use a variable that doesn't exist and has not been declared, then JavaScript will throw an error var name is not defined
and the script will stop executing thereafter. But If you use typeof undeclared_variable
then it will return undefined
.
declaration vs definition
var x
is a declaration because you are not defining what value it holds yet, but you are declaring its existence and the need for memory allocation.
var x = 1
is both declaration and definition (also we can say we are doing initialisation).
Every variable declaration and function declaration brings to the top of its current scope in which it's declared then assignment happen in order this term is called hoisting
.
A variable can be declared but not defined. When we try to access it, It will result undefined
.
A variable can be neither declared nor defined. When we try to reference such variable then the result will be not defined
.
== vs ===
== will not check types and === will check whether both sides are of same type.
== converts to its convenient type to have both in same type and then do the comparison.
=== compares the types and values. Hence, if both sides are not same type, answer is always false.
Rule for implicit coercion:
If both operands are same type use ===
undefined == null
If one operands is string another is number, convert string to number
If one is boolean and another is non-boolean, convert boolean to number and then perform comparison
While comparing a string or number to an object, try to convert the object to a primitive type and then try to compare
Be careful while comparing objects, identifiers must reference the same objects or same array.
Special note: NaN, null and undefined will never === another type. NaN does not even === itself.
Object Equality. Comparing objects
2 approaches for testing equality:
Primitives (strings, numbers): are compared by their value
Objects (arrays, dates, and user defined objects) are compared by their reference. Ie. referring to the same location in memory.
Equality check for objects will check whether two objects have same value for same property. To check that:
you can get the keys for both the objects. If the number of properties doesn't match, these two objects are not equal.
check each property whether they have the same value. If all the properties have same value, they are equal.
Limitation:
If one of the property values is itself an object
If one of the property values is NaN (the only value in JavaScript that is not equal to itself?)
If one object has a property with value undefined, while another object doesn't have the property (which thus evaluates as undefined). Btw, you can solve this problem by using hasOwnProperty
typeof vs instanceof
typeof
is an operator that returns a string with the type of whatever you pass.
The typeof
operator checks if a value belongs to one of the seven basic types: number
, string
, boolean
, object
, function
, undefined
or Symbol
.
typeof(null)
will return object
.
instanceof
is much more intelligent: it works on the level of prototypes. In particular, it tests to see if the right operand appears anywhere in the prototype chain of the left. instanceof
doesn’t work with primitive types. It instanceof
operator checks the current object and returns true if the object is of the specified type, for example:
Here dog instanceof Animal
is true since dog
inherits from Animal.prototype
Function vs Method vs Constructor
Functions
The simplest usage:
Methods
Object properties that are functions.
Notice how helloWorld
refer to this
properties of obj. Here it's clear or you might have already understood that this
gets bound to obj
. But the interesting point that we can copy a reference to the same function helloWorld
in another object and get a difference answer. Let see:
You might be wonder what exactly happens in a method call here. Here we call the expression itself determine the binding of this this
, The expression obj2.helloWorld()
looks up the helloWorld
property of obj and calls it with receiver object obj2
.
Constructors
Create and initialize a brand new object and passes it as the value of this
Implicitly returns the new object as its result.
Ways of creating objects
1. Function based
Useful if we want to create several similar objects. In the code sample below, we wrote the function Employee
and used it as a constructor by calling it with the new
operator.
2. Object Literal
The best way to create an object and this is used frequently. Below is code sample for create employee object which contains property as well as method.
The code sample below is Nested Object Literal, Here address is an object inside employee object.
3. new keyword
Example:
4. Object.create()
Object.create(obj)
will create a new object and set the obj
as its prototype.
Modern way to create objects that inherit properties from other objects. Object.create
function doesn’t run the constructor.
Use Object.create(null)
when you don’t want your object to inherit the properties of Object
.
Function statements vs Function expressions
Function statements
Defined at parse-time
Function expressions
Defined at runtime
var
-declared variables and functions are hoisted (JS interpreter looks ahead to find all the variable declaration and hoists them to the top of the function where it's declared).
IIFE's
Immediately Invoked Function Expression
Function that runs as soon as it's defined.
Usually it's anonymous, but it also can be named.
Example:
typeof() vs instanceOf()
typeof()
operator that returns a string with the type of whatever you pass.
Checks if a value belongs to one of the seven basic types: number
, string
, boolean
, object
, function
, undefined
or Symbol
.
typeof(null)
will return object
.
instanceof()
Is much more intelligent: it works on the level of prototypes.
It tests to see if the right operand appears anywhere in the prototype chain of the left.
It doesn’t work with primitive types. It instanceof
operator checks the current object and returns true if the object is of the specified type
Functional vs Object Oriented programming
OOP Pros:
It’s easy to understand the basic concept of objects and easy to interpret the meaning of method calls. OOP tends to use an imperative style rather than a declarative style, which reads like a straight-forward set of instructions for the computer to follow.
OOP Cons
Depends on shared state. Objects and behaviors are typically tacked together on the same entity, which may be accessed at random by any number of functions with non-deterministic order, which may lead to undesirable behavior such as race conditions.
FP Pros
FP avoids any shared state or side-effects: eliminates bugs caused by multiple functions competing for the same resources. With features such as the availability of point-free style (aka tacit programming), functions tend to be radically simplified and easily recomposed for more generally reusable code compared to OOP.
Favors declarative and denotational styles, which do not spell out step-by-step instructions for operations, but instead concentrate on what to do, letting the underlying functions take care of the how. This leaves tremendous latitude for refactoring and performance optimization, even allowing you to replace entire algorithms with more efficient ones with very little code change. (e.g., memoize, or use lazy evaluation in place of eager evaluation.)
Easy to scale across multiple processors, or across distributed computing clusters without fear of threading resource conflicts, race conditions, etc…
FP Cons
Over exploitation can potentially reduce readability because the resulting code is often more abstractly specified, more terse, and less concrete.
More people are familiar with OO and imperative programming than functional programming, can be confusing.
Steeper learning curve than OOP.
Closures
Inner function that has access to the variables in the outer (enclosing) function’s scope chain, even after the outer function has returned.
To use a closure: define a function inside another function and expose it (return it or pass it to another function).
Have access to variables in 3 scopes:
Its own scope
The enclosing function’s scope
Global variables
Example:
Variables from innerFunc
, outerFunc
, and the global namespace are all in scope in the innerFunc
.
Output:
Uses
To give objects data privacy: the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods.
To create stateful functions whose return values may be influenced by their internal state, e.g.:
const secret = msg => () => msg;
In functional programming: for partial application & currying
Currying
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.
Useful for making code written in a functional style easier to read and compose.
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.
References
Monolithic vs Microservice architectures
Monolithic architecture
App is written as one cohesive unit of code whose components are designed to work together, sharing the same memory space and resources.
Pros
Most apps typically have a large number of cross-cutting concerns, such as logging, rate limiting, and security features such audit trails and DOS protection. When everything is running through the same app, it’s easy to hook up components to those cross-cutting concerns.
Performance advantages, since shared-memory access is faster than inter-process communication (IPC).
Cons
Tightly coupled and entangled as the application evolves. Difficult to isolate services for purposes such as independent scaling or code maintainability.
Harder to understand: dependencies, side-effects.
Microservice architecture
App is made up of lots of smaller, independent applications capable of running in their own memory space and scaling independently from each other across potentially many separate machines.
Microservice pros
Better organized. Each microservice has a very specific job, and is not concerned with the jobs of other components. Decoupled services are also easier to recompose and reconfigure to serve the purposes of different apps.
Performance advantages: independently scalable microservices.
Microservice cons
As you’re building a new microservice architecture, you’re likely to discover lots of cross-cutting concerns that you did not anticipate at design time. A monolithic app could establish shared magic helpers or middleware to handle such cross-cutting concerns without much effort.
Overhead of separate modules for each cross-cutting concern, or encapsulate cross-cutting concerns in another service layer that all traffic gets routed through. Eventually, even monolthic architectures tend to route traffic through an outer service layer for cross-cutting concerns, but with a monolithic architecture, it’s possible to delay the cost of that work until the project is much more mature.
Frequently deployed on their own virtual machines or containers, causing a proliferation of VM wrangling work. These tasks are frequently automated with container fleet management tools.
Performance overhead caused by IPC and network communication.
Two-way data binding vs One-way data flow
Two-way data binding
UI fields are bound to model data dynamically
When a UI field changes, the model data changes with it and vice-versa.
Example: Angular
One-way data flow
The model is the single source of truth.
Changes in the UI trigger messages that signal user intent to the model (or “store” in React)
Only the model has the access to change the app’s state. The effect is that data always flows in a single direction, which makes it easier to understand.
Example: React
Event delegation
Adding event listeners to a parent element instead of adding them to the descendant elements.
The listener will fire whenever the event is triggered on the descendant elements due to event bubbling up the DOM.
Attach a single event listener, to a parent element, that will fire for all children matching a selector, whether those children exist now or are added in the future. The underlying mechanism is browser's event bubbling .
Benefits:
Memory footprint goes down. Only one single handler is needed on the parent element, rather than having to attach event handlers on each descendant.
No need to unbind the handler from elements that are removed and to bind the event for new elements.
References
Event bubbling
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
.
The mechanism behind event delegation.
Code organization (modeula pattern, classical inheritance)
call() vs 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.
.call
takes in comma-separated arguments as the next arguments
.apply
takes in an array of arguments as the next argument.
Way to remember this is C for call
and comma-separated and A for apply
and an array of arguments.
strict mode
'use strict';
enables strict mode to entire scripts or individual functions.
Strict mode is a way to opt into a restricted variant of JavaScript.
Advantages:
Impossible to accidentally create global variables.
Assignments which would otherwise silently fail to throw an exception.
Attempts to delete undeletable properties throw (where before the attempt would simply have no effect).
Requires that function parameter names be unique.
this
is undefined in the global context.Catches some common coding bloopers, throwing exceptions.
Disables features that are confusing or poorly thought out.
Disadvantages:
Many missing features that some developers might be used to.
No more access to
function.caller
andfunction.arguments
.Concatenation of scripts written in different strict modes might cause issues.
Overall, I think the benefits outweigh the disadvantages.
Cloning an object
Now the value of objclone is {a: 1 ,b: 2}
but points to a different object than obj
.
Note the potential pitfall, though: Object.clone()
will just do a shallow copy, not a deep copy. This means that nested objects aren’t copied. They still refer to the same nested objects as the original:
Iterating over object properties and array items
Objects:
for-in loops -
for (var property in obj) { console.log(property); }
. However, this will also iterate through its inherited properties, and you will add anobj.hasOwnProperty(property)
check before using it.Object.keys() -
Object.keys(obj).forEach(function (property) { ... })
.Object.keys()
is a static method that will lists all enumerable properties of the object that you pass it.Object.getOwnPropertyNames() -
Object.getOwnPropertyNames(obj).forEach(function (property) { ... })
.Object.getOwnPropertyNames()
is a static method that will lists all enumerable and non-enumerable properties of the object that you pass it.
Arrays:
for loops
-for (var i = 0; i < arr.length; i++)
. The common pitfall here is thatvar
is in the function scope and not the block scope and most of the time you would want block scoped iterator variable. ES2015 introduceslet
which has block scope and it is recommended to use that instead. So this becomes:for (let i = 0; i < arr.length; i++)
.forEach -
arr.forEach(function (el, index) { ... })
. This construct can be more convenient at times because you do not have to use theindex
if all you need is the array elements. There are also theevery
andsome
methods which will allow you to terminate the iteration early.
Most of the time, I would prefer the .forEach
method, but it really depends on what you are trying to do. Before ES6, we used for
loops when we needed to prematurely terminate the loop using break
. But now with ES6, we can do that with for-of
loops. I would use for
loops when I need even more flexibility, such as incrementing the iterator more than once per loop.
When using the for-of
loop, if you need to access both the index and value of each array element, you can do so with the ES6 Array entries()
method and destructuring:
Add an element at the beginning / end of an array
With ES6, one can use the spread operator:
Or, in short:
Last updated