Skip to content

Latest commit

 

History

History
972 lines (722 loc) · 28.7 KB

javascript-qa.md

File metadata and controls

972 lines (722 loc) · 28.7 KB

What is asynchronous programming, and why is it important in JavaScript?

  • Synchronous programming means that, barring conditionals and function calls, code is executed sequentially from top-to-bottom, blocking on long-running tasks such as network requests and disk I/O.
  • Asynchronous programming means that the engine runs in an event loop. When a blocking or, long time operation is needed, the request is started, and the code keeps running without blocking for the result (running in other place). When the response is ready, and interrupt is fired, which causes an event handler to be run, where the control flow continues. In this way, a single program thread can handle many concurrent operations.
  • User interfaces are asynchronous by nature!
  • Good to hear:
    • An understanding of what is blocking means, and the performance implications.
    • An understanding of event handling, and why its important for UI code
  • Red flags:
    • Unfamiliar with the terms asynchronous or synchronous
    • Unable to articulate performance implications or the relationship between asynchronous code and UI code.

Ref

Explain Event Delegation

Js event listeners fire not only a single DOM but on all it's descendants

Describe Event Bubbling ('bubble up')

Also known as "propogation". Events on an element will "bubble up" and also fire on all parents.

What are benefits of a named function over a anonymous function?

  • Handy function self-reference: necessary when referencing from inside the function, e.g. recursion
  • More debuggable stack traces: helpful when seeing stack trace while debugging
  • More self-documenting code: when using the function as callback it is more documented

So, in production code we should use Name Function always.

Difference between target and currentTarget?

target is actual thing what is clicked and currentTarget is where the event listener is attached to.

How to Check for null?

null is a primitive type in JavaScript that represents an intentional absence of a value -- it is set on-purpose

  • One way to check for null is JS is to check if a value loosely equal to null using double equality (==) operator:
console.log(null == null); // true
console.log(null == undefined); // true!

So, null is only loosely equal to itself and undefined (not to the other falsy values).

  • Other way is to check using strict equality (===)
console.log(null == null); // true
console.log(null == undefined); // false

so, that's perfect!

  • An alternative method of checking for null is based on knowing that null is falsy, but empty objects are truthy, so null is the only falsy object.
console.log(typeof null === 'object' && !null); // true
console.log(typeof {} === 'object' && !{}); // false

The value null is falsy but empty objects are truthy, so typeof null === "object" && !null is a convenient way to check for null.

Explain the difference on the usage of following -

function foo() {
  // I am known as a definition or statement
}
var foo = function () {
  // i am an expression, i resolve to a value, even if just 'undefined'
  // expression = MDN - an expression is any valid unit of code that resolves to a value
};

What is Factory Function?

Any function that returns a new object which is not a Constructor function (not called with new keyword).

Difference between a variable that is: null, undefined, or undeclared

  • Undeclared: never used/defined before const bar = foo + 1;

    console.log(typeof bar); // undeclared, but also returns "undefined"

  • Undefined:

    • variable declared but no defined value (not initialized)

    • object/array exists but nothing at that key/index

    • function exists but doesn't return anything

    • falsy

      let foo;
      const bar = foo; // foo is undefined
      console.log(typeof foo); // "undefined" as a string
      console.log(foo === undefined); // true boolean
      const baz = 'undefined';
      console.log(baz === undefined); // false. Hooray, I guess
  • null:

    • null has a value. It's value is null
    • null is a "nothing" value
    • not zero, not an empty string/object/array
    • falsy
    let foo = null;
    console.log(foo === null); // true boolean

What is the JavaScript Principles When Code Runs?

Two Principles:

  1. Goes through the code line-by-line and runs/executes each line -- known as the thread of execution
  2. Saves data like strings and arrays so we can use that data later -- in its memory (we can even save code e.g. functions)

What does JavaScript get or getter keyword do?

The get syntax binds an object property to a function that will be called when that property is looked up.

Note:

  • It can have an identifier which is either a number or a string
  • It must have exactly zero parameters
  • It must not appear in an object literal with another get or with a data entry for the same property. e.g. { get x() }, get x() {}) and { x: ..., get x() {}} are forbidden.

Examples:

Defining a getter on new objects in object initializers

const obj = {
  log: ['foo', 'bar'],
  get latest() {
    if (this.log.length === 0) return undefined;
    return this.log[this.log.length - 1];
  }
}
console.log(obj.latest); // "bar"

  ```

- Deleting a getter using the `delete` operator

```js
delete obj.latest;

Defining a getter on existing objects using defineProperty.

var o = { a: 0 };
Object.defineProperty(o, 'b', {
  get: function () {
    return this.a + 1;
  },
});

console.log(o.b); // runs the getter, which yeilds a + 1

Using a computed property name

const name = 'foo';

const o = {
  get [name]() {
    return 'bar';
  },
};

console.log(o.foo); // "bar"

Get vs defineProperty()

When using get the property will be defined on the property of the object while using Object.defineProperty() the property will be defined on the instance it is applied to.

class Foo {
  get hello() {
    return 'world';
  }
}

const o = new Foo();
console.log(o.hello); // "world"

console.log(Object.getOwnPropertyDescriptor(o, 'hello')); // undefined

console.log(Object.getOwnPropertyDescriptor(Object.getPrototypeOf(o), 'hello'));
// // { configurable: true, enumerable: false, get: function get hello() { return 'world'; }, set: undefined }

Comparison

Compare null, undefined, NaN

A null value represents nothing, nonexistent or invalid object or address. It converts to 0 in simple arithmetic operations and it's global object. null == false gives us false.

The global undefined property represents the primitive value undefined. It tells us something has not assigned value; isn't defined. undefined isn't converted into any number, so using it in maths calculations returns NaN.

NaN (Not-A-Number) represents something which is not a number, even though it's actually a number. It's not equal to itself and to check if something is NaN we need to use isNaN() function.

All of the above are falsy values so they convert to false.

Ref

What Gets Logged in Various Sorting Conditions?

const arr1 = ['a', 'b', 'c'];
const arr2 = ['b', 'c', 'a'];

console.log(
  arr1.sort() === arr1,
  arr2.sort() == arr2,
  arr1.sort() === arr2.sort()
);

// output: true true false

Explanation: the array sort() method sorts the original array and returns a reference to that array. The sort order of the array doesn't matter when we're comparing objects. Since arr1.sort() and arr1 point to the same object in the memory, the first equality test return true.

Second comparison also return true for same reason.

Third comparison returns false cause the sort order of arr1.sort() and arr2.sort() are the same; however, they still point to different objects in memory.

Miscellaneous

What is the output?

const str = 'constructor';

console.log(str[str](01));

Answer 1 --> str.constructor(01) returns "1"

What is the output?

function b() {
  console.log(`the length is ${this.length}!`);
}

let a = {
  length: 10,
  getLength: function(b) {
    arguments[0]();
  }
}

a.getLength(b, 5);

Answer: "the length is 2!" -- cause inside b() this = arguments!

What is the output?

function printIt(value) {
  return 'Hello ';
}

const string = printIt `World`;

console.log(string);

Answer: Hello

Output of following snippet?

function foo() {
  let a = (b = 0);
  // declares a local variable 'a' and a global variable 'b'. There is no variable 'b' declared in the foo() scope or global scope. So JS interprets 'b=0' expression as window.b = 0
  a++;
  return a;
}

foo();
typeof a; // ???
// 'undefined' -> 'a' is declared within 'foo()' scope
typeof b; // ???
// 'number' -> 'b' is global variable with value 0

What if we set the Array.length = 0 manually?

const arr = ['sajib', 'khan'];
arr.length = 0;

arr[0]; // ???

If we reduce the value of the length property has the side-effect of deleting own array elements whose array index is between the old and new length values.

So, when JS executes arr.length = 0, all the items of the array arr are deleted.

Answer: undefined

What is the two conditions of being a Module?

  1. There must be an outer enclosing function that executes at least one.
  2. From inside that functions return at least one inner function(s).
// example 1
var myModule = (function () {
  'use strict';

  return {
    publicMethod: function () {
      console.log('Hello World!');
    },
  };
})();

myModule.publicMethod(); // Hello World!
// example 2
define('foo', function () {
  // define run the function automatically and assign the return value in 'foo'
  var o = { bar: 'bar' };
  return {
    bar: function () {
      console.log(o.bar);
    },
  };
});

One important thing is to the File content is also a module. e.g. ES6 + module pattern

  • By default, File based module is singletone, mean it has only one instance. If we import the File from inside different files it creates only one instance and share with all.
// foo.js
var o = { bar: 'bar' };

export function bar() {
  console.log(o.bar);
}

import { bar } from 'foo.js';

bar(); // bar

import * as foo from 'foo.js';

foo.bar(); // bar

How to Prevent adding new properties to an object?

We can use Object.preventExtensions() method to prevent adding new properties to an object:

'use strict';

let myObj = {
  one: 1,
  two: 2
};

console.log(myObj.one); // 1
console.log(myObj.two); // 2

Object.preventExtensions(myObj);

try {
  myObj.three = 3;
} catch (e) {
  console.log(e.message);
  // "Cannot add property three, object is not extensible" }

console.log(myObj.three); // undefined
  • In strict mode browser will throw the error shown in the catch block
  • In non-strict node, browser attempt will just fail silently
  • We can still delete properties, unlike when using Object.freeze()
  • This prevents addition of own properties, but we can still add to the object's prototype

How to get Unique values of an Array?

const uniqueValues = [...new Set([1, 2, 3, 3])];
console.log(uniqueValues);
// [1, 2, 3]

How can remove all falsy values from an Array?

const onlyTrueValues = [0, 1, "Alice", undefined, null, false, "Bob"
  .map(item => {
    // ...
  }).filter(Boolean);

console.log(onlyTrueValues);
// [1, "Alice", "Bob"]

How to Apply Style in Console Message

console.log(
  '%c This is a styled message',
  'background: #222; color: #bada55; font-size: 14px; padding: 5px'
);

So, here is some example we can use console in different way:

// log a variable
const fruit = 'Apple';
console.log({ fruit }); // {fruit: "Apple"}

// %s replaces an element with a string
console.log('Hello I love %s', 'Javascript');

// %d  replaces an element with an integer
console.log('Hello %d ', 1);

// %f  replaces an element with a float
console.log('Hello  %f ', 1.078);

// %(o|O) | element is displayed as an object.
console.log('Hello %O', { Name: 'Sidd' });

// %c | Applies the provided CSS
console.log('%cThis is a red text', 'color:red');

How to create an Empty Objects?

let emptyArr = Object.create(null);
// emptyArr.__proto__ === "undefined"

Swap Two Numbers without using Third Variable?

let a = 10;
let b = 20;
console.log(a, b); // OUTPUT: 10, 20
[a, b] = [b, a];
console.log(a, b); // OUTPUT: 20, 10

How to require function parameters by force?

const isRequired = () => {
  throw new Error('param is required');
};

const sayHello = (name = isRequired()) => {
  console.log(`Hello ${name}`);
};

sayHello(); // throw an error
sayHello(undefined); // throw an error

sayHello(null); // no error!!
sayHello('Sajib'); // no error

How to get Query String Parameters?

// say, "?post=1234&action=edit"
const urlParams = new URLSearchParams(window.location.search);

console.log(urlParams.has('post')); // true
console.log(urlParams.get('action')); // "edit"
console.log(urlParams.getAll('action')); // ["edit"]
console.log(urlParams.toString()); // "?post=1234&action=edit"
console.log(urlParams.append('active', '1')); // "?post=1234&action=edit&active=1"

What is Debouncing in JavaScript?

There are some browser events that can fire many times within a short timespan very quickly, such as resizing a window or scrolling down page. This can cause a serious performance issues.

Debouncing is one way to solve this issue by limiting the time that needs to pass by until a function is called. So, it limits the rate at which a function can fire.

// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
function debounce(func, wait, immediate) {
  var timeout;
  return function () {
    var context = this,
      args = arguments;
    var later = function () {
      timeout = null;
      if (!immediate) func.apply(context, args);
    };
    var callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
    if (callNow) func.apply(context, args);
  };
}

// another implementation
const debounce = (func, timer) => {
  let timeId = null;
  return (...args) => {
    if (timeId) {
      clearTimeout(timeId);
    }
    timeId = setTimeout(() => {
      func(...args);
    }, timer);
  };
};

document.querySelector('input').addEventListener(
  'keyup',
  debounce((e) => {
    console.log('e: ', e);
  }, 1000)
);

This function - when wrapped around an event - will execute only after a certain amount of time has elapsed

// function to be called when user scrolls
function foo() {
  console.log('You are scrolling');
}

// wrap our function in a debounce to fire once 2 seconds have gone by
let elem = document.getElementById('container');
elem.addEventListener('scroll', debounce(foo, 2000));

Ref: MDN, FreeCodeCamp

How to determine what should be the this keyword value?

The sequence we should be think is: (priority: top to bottom)

  1. Is the function called by new?
  2. Is the function called by call() or apply()?
  • Note: bind() effectively uses apply()
  1. Is the function called on a context object? e.g. ob.funcA
  2. DEFAULT: global object(except strict mode)

Convert a value to String

Here, 5 ways are described to covert a value to String:

const value = 12345;

// Concat Empty String
value + '';

// Template Strings
`${value}`;

// JSON.stringify
JSON.stringify(value);

// toString()
value.toString();

// String()
String(value);

// RESULT
// '12345'

Let's compare some different type of variables converting to String

// string
const string = 'hello';
string + ''; // 'hello'
`${string}`; // 'hello'
JSON.stringify(string); // '"hello"'
string.toString(); // 'hello'
String(string); // 'hello'

// number
const number = 123;
number + ''; // '123'
`${number}`; // '123'
JSON.stringify(number); // '123'
number.toString(); // '123'
String(number); // '123'

// boolean
const boolean = true;
boolean + ''; // 'true'
`${boolean}`; // 'true'
JSON.stringify(boolean); // 'true'
boolean.toString(); // 'true'
String(boolean); // 'true'

// array
const array = [1, '2', 3];
array + ''; // '1,2,3'
`${array}`; // '1,2,3'
JSON.stringify(array); // '[1,"2",3]'
array.toString(); // '1,2,3'
String(array); // '1,2,3'

// object
const object = { one: 1 };
object + ''; // '[object Object]'
`${object}`; // '[object Object]'
JSON.stringify(object); // '{"one":1}'
object.toString(); // '[object Object]'
String(object); // '[object Object]'

// symbol
const symbolValue = Symbol('123');
symbolValue + ''; // ❌ TypeError
`${symbolValue}`; // ❌ TypeError
JSON.stringify(symbolValue); // undefined
symbolValue.toString(); // 'Symbol(123)'
String(symbolValue); // 'Symbol(123)'

// undefinedValue
const undefinedValue = undefined;
undefinedValue + ''; // 'undefined'
`${undefinedValue}`; // 'undefined'
JSON.stringify(undefinedValue); // undefined
undefinedValue.toString(); // ❌ TypeError
String(undefinedValue); // 'undefined'

// nullValue
const nullValue = null;
nullValue + ''; // 'null'
`${nullValue}`; // 'null'
JSON.stringify(nullValue); // 'null'
nullValue.toString(); // ❌ TypeError
String(nullValue); // 'null'

We can see that String() handle the null and undefined quite well. No errors are thrown - unless that what we want. If we are not sure about our data type then String() is always good by default.

Reference

Convert a string to spinal string.

Spinal string case is all-lowercase-words-joined-by-dashes

// Input:
This Is Spinal Tap
thisIsSpinalTap
The_Andy_Griffith_Show
Teletubbies say Eh-oh
AllThe-small Things

// Output:
this-is-spinal-tap
this-is-spinal-tap
the-andy-griffith-show
teletubbies-say-eh-oh
all-the-small-things

Solutions:

function spinalCase(str) {
  // Create a variable for the white space and underscores
  var regex = /\s+|_+/g;

  // Replace low-upper case to low-space-uppercase
  str = str.replace(/([a-z])([A-Z])/g, '$1 $2');

  // Replace space and underscore with -
  return str.replace(regex, '-').toLowerCase();
}

// test here
spinalCase('This Is Spinal Tap');

What type of scoping rule(s) does JavaScript have?

  • Lexical scope

What are 3 different ways we can create a new scoped variable?

  • Let inside a scope
  • Var inside a function
  • err in catch close: e.g. catch(err) { ... }

What are the four things the new keyword actually does when we put in front of a function call (aka: constructor call)?

  1. Create a brand new empty object (aka constructed) out of thin air.
  2. Newly created/constructed object is linked to ([[Prototype]]) the function's prototype.
  3. Newly created/constructed object is set as the this binding for that function call.
  4. Unless the function returns its own alternate object, the new-invoked call will automatically return the newly constructed object.

What is the different between undeclared and undefined?

Undeclared: It's never been declared in any scoped we have accessed to Undefined: It has beed in a scope but it does not have currently any value

What is the only value in JS that is not equal to itself? How to check 'NaN?

NaN (not a number) is the only value that is not equal to itself.

if (!Number.isNaN) {
  Number.isNaN = function isNaN(x) {
    return x !== x;
    // NaN === NaN -- false
  };
}

The isNaN() function determines whether a value is NaN or not.

const a = NaN, b = 5;
isNaN(a); // true

isNaN(b); // false

isNaN('test'); // true, surprising!!

Coercion inside the isNaN function can be surprising so we can use Number.isNaN() method determines whether the passed value is NaN and its type is Number. It is a more robust version of the original, global isNaN().

Number.isNaN('test'); // false

Tips: typeof(NaN) returns number!

How to Prevent User from Pasting Text

if we want to prevent the user from pasting text into inputs by javascript we can use paste event listeners

<input type="text"></input>
<script>
  // selecting the input.
  const input = document.querySelector('input');

  // prevent the user to paste text by using the paste eventListener.
  input.addEventListener("paste", function(e){
    e.preventDefault()
  })
</script>

What does happens when we declare a variable with var and let?

Declaring with var two things are happened:

  1. Hoist the variable at compile time.
  2. Initialize the Hoisted variable with undefined at runtime.

Declaring with let only one thing is happened:

  1. Hoist the variable
function foo(bar) {                       | var a;      // undefined
  if (bar) {                              | if (bar) {
    console.log(baz);  // ReferenceError  |  let baz;   // uninitialized
    let baz = bar;                        |  console.log(baz);
    var a;                                |  let baz = bar;
  }                                       |
}                                         |

So, let is hoisted but not initialized actually.

Implement an Event Emitter that supports standard operations

Using ES2015 classes:

class EventEmitter {
  constructor() {
    this.events = {};
  }
  on(event, listener) {
    if (typeof this.events[event] !== 'object') {
      this.events[event] = [];
    }
    this.events[event].push(listener);
    return () => this.off(event, listener);
  }
  off(event, listener) {
    if (typeof this.events[event] === 'object') {
      const idx = this.events[event].indexOf(listener);
      if (idx > -1) {
        this.events[event].splice(idx, 1);
      }
    }
  }
  emit(event, ...args) {
    if (typeof this.events[event] === 'object') {
      this.events[event].forEach((listener) => listener.apply(this, args));
    }
  }
  once(event, listener) {
    const remove = this.on(event, (...args) => {
      // tricky, think how it's working!
      remove();
      listener.apply(this, args);
    });
  }
}

Using plain prototype with factory function

const anEventEmitter = {
  events: {},
  on(event, listener) {
    if (this.events[event] !== 'object') {
      this.events[event] = [];
    }
    this.events[event].push(listener);

    return () => this.off(event, listener);
  }

  off(event, listener) {
    if(this.events[event] === 'object') {
      const idx = this.events[event].indexOf(listener);
      if (idx > -1) {
        this.events[event].splice(idx, 1);
      }
    }
  }

  emit(event, ...args) {
    if (this.events[event] === 'object') {
      this.events[event].forEach(listener => listener.apply(this, args));
    }
  }

  once(event, listener) {
    const remove = this.on(event, (...args) => {
      remove();
      listener.apply(this, args);
    });
  }
};

const EventEmitter = () => ({
  __proto__: anEventEmitter,
  events: {}
})

Ref

Live Reloading vs Hot Reloading

  • Live Reloading relaods or refreshes the entire app when a file changes. For example, if we have four links deep into our navigation and saved a change, live reloading would restart the app and load the app back to the initial route.
  • Hot Reloading only refreshes the files that were changed without losing the state of the app. If we have four links deep into our navigation and saved a change to some styling, the state would not change, but the new styles would appear on the page without having to navigate back to the page we are on because we would still be on the same page

Reference

How to write optimized JavaScript

  1. Order of object properties: always instantiate our object properties in the same order so that hidden classes, and subsequently optimized code, can be shared.
  2. Dynamic properties: adding properties to an object after instantiation will force a hidden class change and slow down any methods that were optimized for the previous hidden class. Instead, assign all of an object's properties in its constructor.
  3. Methods: code that executes the same method repeatedly will run faster than code that executes many different methods only once (due to inline caching).
  4. Arrays: avoid sparse arrays where keys are not incremental numbers. Sparse arrays which don't have every element inside them are a hash table. Elements in such arrays are more expensive to access. Also, try to avoid pre-allocating large arrays. It's better to grow as you go. Finally, don't delete elements in arrays. It makes the keys sparse.
  5. Tagged values: V8 represents objects and numbers with 32 bits. It uses a bit to know if it is an object (flag = 1) or and integer (flag = 0) called SMI (SMall Integer) because of its 31 bits. Then, if a numeric value is bigger that 31 bits, V8 will box the number, turning it into a double and creating a new object to put the number inside. Try to use 31 bit signed numbers whenever possible to avoid teh expensive boxing operation into a JS object.

Ref:

What are the checklists that you follow for reviewing frontend code

========================================================================

  • Make sure the code works
  • Code is easily understand, written following the coding standards (React/Redux in our case), sync with existing code patterns
  • Check if it is possible to refactor to reduce duplication, write generic/re-useable code!
  • Meaningful names for variables/classes/methods and following the standard convention.
  • Handle JavaScript exceptions, errors, promise rejections and api errors properly
  • Keep functions/classes/components small, use Functional components where needed instead Class component, avoid infinite loop- while updating state, avoid using nested if/else statements
  • When new library is needed for a feature check for library size -- if lightweight (+popular) library present then check it out
  • Clean code: remove unused/unreachable code/packages, keep only the useful comments, no console logs
  • Check how component/page looks in different browsers (desktop and mobile)
  • Check security: SQL injection, Cross-site Scripting (XSS), etc.
  • Tests are readable, maintainable, trustworthy (though we're not following this now-a-days)
  • Git commits are small, divided into logical parts, understandable, use branches for new feature/fix

======================================================

Some questions to check:

OOP

  • How does this changes in different context? How many contexts are there?
  • What is a prototype in JavaScript?
  • How do you create objects in JavaScript?
  • What is the module pattern? When do you use it?
  • What is the factory pattern? When do you use it?
  • FP
  • What is immutability?
  • What array methods are immutable?
  • How do you change JavaScript properties while not mutating the object?
  • What is a pure function?
  • How many kinds of actions should a function contain?
  • What are side effects?
  • How do you handle side effects when you write pure functions?
  • AJAX
  • What are JavaScript promises?
  • How do you chain promises?
  • How do you catch errors when using promises?
  • How do you use the Fetch API?
  • What does CRUD stand for?
  • How do you query Github’s API to get a list of your own repositories?
  • Best practices
  • Why do you avoid global variables?
  • Why use strict equality (===) instead of normal equality (==)?
  • How do you use ternary operators to help you write terser code?
  • What ES6 features help you write terser code?
  • What is event bubbling and capturing?
  • How do you delegate events?
  • How do you remove event listeners? When should you remove them?