Skip to content

smeekas/JS-coding-question

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

96 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

JS coding Questions

  1. Async helper Sequence()
    You are asked to implement an async function helper, sequence() which chains up async functions.
    Your sequence() should accept AsyncFunc array, and chain them up by passing new data to the next AsyncFunc through data in Callback.

    //All async functions have following interface
    type Callback = (error: Error, data: any) => void;
    
    type AsyncFunc = (callback: Callback, data: any) => void;

    Once an error occurs, it should trigger the last callback without triggering the uncalled functions.
    ex.

    const asyncTimes2 = (callback, num) => {
      setTimeout(() => callback(null, num * 2), 100);
    };
    
    const asyncTimes4 = sequence([asyncTimes2, asyncTimes2]);
    
    asyncTimes4((error, data) => {
      console.log(data); // 4
    }, 1);
  2. Async helper Parallel()
    You are asked to implement an async function helper, parallel() which works like Promise.all(). Different from sequence(), the async function doesn't wait for each other, rather they are all triggered together.

    //All async functions have following interface
    type Callback = (error: Error, data: any) => void;
    
    type AsyncFunc = (callback: Callback, data: any) => void;

    When error occurs, only first error is returned. Later errors or data are ignored.
    ex.

    const async1 = (callback) => {
      callback(undefined, 1);
    };
    
    const async2 = (callback) => {
      callback(undefined, 2);
    };
    
    const async3 = (callback) => {
      callback(undefined, 3);
    };
    
    const all = parallel([async1, async2, async3]);
    
    all((error, data) => {
      console.log(data); // [1, 2, 3]
    }, 1);
  3. Async helper Race()
    You are asked to implement an async function helper, race() which works like Promise.race(). Different from parallel() that waits for all functions to finish, race() will finish when any function is done or run into error.
    Your race() should accept AsyncFunc array, and return a new function which triggers its own callback when any async function is done or an error occurs.

    //All async functions have following interface
    type Callback = (error: Error, data: any) => void;
    
    type AsyncFunc = (callback: Callback, data: any) => void;

    When error occurs, only first error is passed down to the last. Later errors or data are ignored.
    ex.

    const async1 = (callback) => {
      setTimeout(() => callback(undefined, 1), 300);
    };
    
    const async2 = (callback) => {
      setTimeout(() => callback(undefined, 2), 100);
    };
    
    const async3 = (callback) => {
      setTimeout(() => callback(undefined, 3), 200);
    };
    const first = race([async1, async2, async3]);
    
    first((error, data) => {
      console.log(data); // 2, since 2 is the first to be given
    }, 1);
  4. Promise.all() polyfill
    Write function all which should works the same as Promise.all().

  5. Promise.allSettled() polyfill
    Write function allSettled which should works the same as Promise.allSettled().

  6. Promise.race() polyfill
    Write function race which should works the same as Promise.race().

  7. lodash once()
    _.once(func) is used to force a function to be called only once, later calls only returns the result of first call.

  8. lodash Chunk()
    _.chunk(func) splits array into groups with the specific size.

    chunk([1, 2, 3, 4, 5], 1);
    // [[1], [2], [3], [4], [5]]
    chunk([1, 2, 3, 4, 5], 2);
    // [[1, 2], [3, 4], [5]]
    
    chunk([1, 2, 3, 4, 5], 3);
    // [[1, 2, 3], [4, 5]]
  9. height of dom tree
    If given DOM tree, can you create a function to get the height of it?
    For the DOM tree below, we have a height of 4.

    <div>
      <div>
        <p>
          <button>Hello</button>
        </p>
      </div>
      <p>
        <span>World!</span>
      </p>
    </div>
  10. auto-retry Promise on rejection
    You are asked to create a fetchWithAutoRetry(fetcher, count), which automatically fetch(call function) again when error happens, until the maximum count is met.
    for simplicity assume fetcher function doesn't accept any argument

  11. get DOM tags
    Given a DOM tree, please return all the tag names it has.
    Your function should return a unique array of tags names in lowercase, order doesn't matter.

  12. Local Storage With expiration
    Please create a localStorage wrapper with expiration support.
    example:-

    myLocalStorage.setItem("token", "value", 1000);
    myLocalStorage.getItem("token"); // 'value'
    
    //after 1 second
    myLocalStorage.getItem("token"); // null
  13. Lazy Man
    LazyMan is very lazy, he only eats and sleeps.
    LazyMan(name: string, logFn: (log: string) => void) would output a message, the passed logFn is used.

    LazyMan("Jack", console.log);
    // Hi, I'm Jack.

    He can eat(food: string)

    LazyMan("Jack", console.log).eat("banana").eat("apple");
    // Hi, I'm Jack.
    // Eat banana.
    // Eat Apple.

    He also sleep(time: number), time is based on seconds.

    LazyMan("Jack", console.log).eat("banana").sleep(10).eat("apple").sleep(1);
    // Hi, I'm Jack.
    // Eat banana.
    // (after 10 seconds)
    // Wake up after 10 seconds.
    // Eat Apple.
    // (after 1 second)
    // Wake up after 1 second.

    He can sleepFirst(time: number), which has the highest priority among all tasks, no matter what the order is.

    LazyMan("Jack", console.log)
      .eat("banana")
      .sleepFirst(10)
      .eat("apple")
      .sleep(1);
    // (after 10 seconds)
    // Wake up after 10 seconds.
    // Hi, I'm Jack.
    // Eat banana
    // Eat apple
    // (after 1 second)
    // Wake up after 1 second.

    Please create such LazyMan()

  14. Function.prototype.call() polyfill

  15. Function.prototype.bind() polyfill

  16. lodash cloneDeep()
    _.cloneDeep could be very useful for creating deep copies.
    The lodash implementation actually covers a lot of data types, for simplicity, we will just need to cover

    • primitive types and their wrapper Object
    • Plain Objects (Object literal) with all enumerable properties
    • Array
  17. Convert Html to JSON
    Write a function that takes a DOM node as input and converts it to the JavaScript object. The object should have the type of node, its attributes, and all the children.
    example

    // Input:
    // <div id="foo">
    //   <h1>Hello</h1>
    // </div>
    const node = document.getElementById("foo");
    console.log(HTMLtoJSON(node));
    /*
    Output:
    {
      type: "div",
      props: {
        id: "foo",
      },
      children: [
        {
          type: "h1",
          children: "Hello",
        },
      ],
    }
    */
  18. lodash Partial()
    please create your own partial().

    const func = (...args) => args;
    
    const func123 = partial(func, 1, 2, 3);
    
    func123(4);
    // [1,2,3,4]

    It should also support placeholder.

    const _ = partial.placeholder;
    const func1_3 = partial(func, 1, _, 3);
    
    func1_3(2, 4);
    // [1,2,3,4]
  19. Support Negative Indexes to Array write a wrapper function to make negative array index possible.

    const originalArr = [1, 2, 3];
    const arr = wrap(originalArr);
    
    arr[0]; // 1
    arr[1]; // 2
    arr[2]; // 3
    arr[3]; // undefined
    arr[-1]; // 3
    arr[-2]; // 2
    arr[-3]; // 1
    arr[-4]; // undefined

    All methods on arr should be applied to the original array, which means.

    arr.push(4);
    arr[3]; // 4
    originalArr[3]; // 4
  20. Throttle Promises
    If you use Promise.all(), and send 100 requests then 100 requests go to your server at the same time, which is a burden to low spec servers.
    Can we throttle API calls so that always maximum N API calls happens at the same time?
    example

    //callApis:(()=>Promise)[]
    throttleAsync(callApis, 5)
      .then((data) => {
        // the data is the same as `Promise.all`
      })
      .catch((err) => {
        // any error occurs in the callApis would be relayed here
      });
  21. Lodash isEqual()
    _.isEqual is useful when you want to compare complex data types by value not the reference. The lodash version covers a lot of data types. In this problem, we will support :

    • primitives
    • plain objects (object literals)
    • array

    Objects are compared by their own, not inherited, enumerable properties.

    const a = { a: "bfe" };
    const b = { a: "bfe" };
    
    isEqual(a, b); // true
    a === b; // false
    
    const c = [1, a, "4"];
    const d = [1, b, "4"];
    
    isEqual(c, d); // true
    c === d; // false
    
    // circular dependencies
    const a = { name: "dev" };
    a.self = a;
    const b = { name: "dev" };
    b.self = b;
    
    isEqual(a, b); // true
    a === b; // false
  22. Immutability Helper
    Implement Immutability Helper update(), which supports following features.

    //{$push:Array} push() all the items in array on the target.
    const arr = [1, 2, 3, 4];
    const newArr = update(arr, { $push: [5, 6] });
    // [1, 2, 3, 4, 5, 6]
    
    //{$set: any} replace the target
    const state = {
      a: {
        b: {
          c: 1,
        },
      },
      d: 2,
    };
    
    const newState = update(state, { a: { b: { c: { $set: 3 } } } });
    /*
       {
         a: {
           b: {
             c: 3,
           },
         },
         d: 2,
       };
    */
    const arr = [1, 2, 3, 4];
    const newArr = update(arr, { 0: { $set: 0 } });
    //  [0, 2, 3, 4]
    
    //{$merge: object} merge object to the location
    const state = {
      a: {
        b: {
          c: 1,
        },
      },
      d: 2,
    };
    
    const newState = update(state, { a: { b: { $merge: { e: 5 } } } });
    /*
    {
      a: {
        b: {
          c: 1,
          e: 5
        }
      },
      d: 2
    }
    */
    
    //{$apply: function} custom replacer
    const arr = [1, 2, 3, 4];
    const newArr = update(arr, { 0: { $apply: (item) => item * 2 } });
    // [2, 2, 3, 4]
  23. custom typeOf
    Write a function to detect data types.
    Besides basic types, you need to also handle also commonly used complex data type including Array, ArrayBuffer, Map, Set, Date and Function.
    The type should be lowercase

  24. Resolve Promise within time limit
    Given an asynchronous function fn and a time t in milliseconds, return a new time limited version of the input function. fn takes arguments provided to the time limited function.

    The time limited function should follow these rules:

    • If the fn completes within the time limit of t milliseconds, the time limited function should resolve with the result.

    • If the execution of the fn exceeds the time limit, the time limited function should reject with the string "Time Limit Exceeded". example

    function myFunction(data: string) {
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve(data);
        }, 300);
      });
    }
    let newFunction = timeLimit(myFunction, 500);
    newFunction("will resolve?")
      .then((data) => {
        console.log(data); // will resolve?
      })
      .catch((err) => {
        console.log(err);
      });
    
    newFunction = timeLimit(myFunction, 200);
    newFunction("will resolve?")
      .then((data) => {
        console.log(data);
      })
      .catch((err) => {
        console.log(err); //Time limit Exceed
      });
  25. Memoize
    Implement a general memo() function, which caches the result once called, so when same arguments are passed in, the result will be returned right away.

    const func = (arg1, arg2) => {
      return arg1 + arg2;
    };
    
    const memoed = memo(func);
    
    memoed(1, 2);
    // 3, func is called
    
    memoed(1, 2);
    // 3 is returned right away without calling func
    
    memoed(1, 3);
    // 4, new arguments, so func is called

    The arguments are arbitrary, so memo should accept an extra resolver parameter, which is used to generate the cache key, like what _.memoize() does.

    const memoed = memo(func, () => "samekey");
    
    memoed(1, 2);
    // 3, func is called, 3 is cached with key 'samekey'
    
    memoed(1, 2);
    // 3, since key is the same, 3 is returned without calling func
    
    memoed(1, 3);
    // 3, since key is the same, 3 is returned without calling func
  26. Debounce
    debounce(func, delay) will returned a debounced function, which delays the invoke.
    Implement such function

  27. Debounce 2
    Along with regular debounce function provide another 2 methods.

    1. cancel() method to cancel pending invocations.
    2. flush() method to immediately invoke any delayed invocations.

    example.

    const debounced = debounce(() => console.log("debounced"), 500);
    debounced();
    debounced.cancel(); //cancel the invocation.
    // no log displayed in console.
    
    debounced();
    debounced.flush(); //delayed function invoked immediately.
    // log will be displayed in console immediately.
  28. Throttle
    throttle(func, delay) will return a throttled function, which will invoke the func at a max frequency no matter how throttled one is called.
    Basically Throttle will rate limit the original function.
    When function is in its throttling phase, we might get more function call which we will ignore, but you have to call last function call after throttling finishes.
    example

    function myFn(arg: number) {
      console.log(arg);
    }
    
    const throttled = throttle(myFn, 5);
    throttled(1); //1
    throttled(2); //ignored
    throttled(3); //ignored
    throttled(4); //ignored
    // assume now throttling phase is finished.
    // we have to call function with argument 4 because it was the last function call during throttling phase.
  29. Memoize one
    Create MemoizeOne function. Unlike memo it only remembers the latest arguments and result(and this(context)).
    Please implement your own memoizeOne(), it takes 2 arguments

    - target function
    - (optional) a equality check function to compare current and last arguments
    
    Default equality check function should be a shallow comparison on array items with strict equal ===.
    
  30. create a browser history
    Please create BrowserHistory class to mimic browser history behavior.
    The common actions relating to history are:

  • new BrowserHistory() - when you open a new tab, it is set with an empty history

  • goBack() - go to last entry, notice the entries are kept so that forward() could get us back

  • forward() - go to next visited entry

  • visit() - when you enter a new address or click a link, this adds a new entry but truncate the entries which we could forward() to.

    // we start with a new tab
    //[]
    
    // We visit A, B, C
    //[A, B, C(here)]
    
    // goBack()
    //[A, B(here), C]
    
    // goBack()
    //[A(here), B, C]
    
    // forward()
    //[A, B(here), C]
    
    //Now if we visit a new url D, since we are currently at B, C is truncated.
    //[A, B, D(here)]
  1. Lodash get
    _.get(object, path, [defaultValue]) is a handy method to help retrieving data from an arbitrary object. if the resolved value from path is undefined, defaultValue is returned.
    example

    const obj = {
      a: {
        b: {
          c: [1, 2, 3],
        },
      },
    };
    
    get(obj, "a.b.c"); // [1,2,3]
    get(obj, "a.b.c.0"); // 1
    get(obj, "a.b.c[1]"); // 2
    get(obj, ["a", "b", "c", "2"]); // 3
    get(obj, "a.b.c[3]"); // undefined
    get(obj, "a.c", "dev"); // 'dev'
  2. Cache API calls
    Implement a function in JavaScript that caches the API response for the given amount of time. If a new call is made between that time, the response from the cache will be returned, else a fresh API call will be made.
    We will use config object if provided. api calls are same if both config object are same.
    If no config object is provided then api calls are same if api paths are same.
    example

    /*
      call(path:string,config?:object)
    */
    const call = cachedApiCall(3000);
    
    call("https://jsonplaceholder.typicode.com/todos/1", {
      keyword: "dev",
    }).then((a) => console.log(a)); //api call
    
    setTimeout(() => {
      call("https://jsonplaceholder.typicode.com/todos/1", {
        keyword: "dev",
      }).then((a) => console.log(a)); // returned from cache
    }, 2500);
    
    setTimeout(() => {
      call("https://jsonplaceholder.typicode.com/todos/1", {
        keyword: "dev",
      }).then((a) => console.log(a)); // new api call
    }, 4000);
  3. getByClassName
    Write a custom function to find all the elements with the given class in the DOM. Simply put, write the polyfill for the getElementByClassName().
    example

    /* INPUT
    <div class="a">
      <div class="b">
        <div class="a">
          <div class="d">d1</div>
        </div>
        <div class="c">
          <div class="a">
            <div class="d">d2</div>
          </div>
        </div>
      </div>
    </div>
    */
    findByClass("d");
    /* OUTPUT
    [
      <div class="d">d1</div>,
      <div class="d">d2</div>
    ]
    */
  4. getByClassNameHierarchy()
    Write a function getByClassNameHierarchy() in javaScript that takes a path of class names and returns the last element of that path.
    example

    /* INPUT
    <div class="a">
      <div class="b">
        <div class="a">
          <div class="d">d1</div>
        </div>
        <div class="c">
          <div class="a">
            <div class="d">d2</div>
          </div>
        </div>
      </div>
    </div>
    */
    getByClassNameHierarchy("a>b>a");
    /* OUTPUT
    [
      <div class="a">
          <div class="d">d1</div>
      </div>,
      <div class="a">
          <div class="d">d2</div>
      </div>
    ]
    */
  5. FindAllElementsByColor
    Write a function to find all the elements with the given color. Here the color will be provided in any format like, plain text (white), HEXA value (#fff or #ffffff), or RGB value (RGB(255, 255, 255)).

  6. Method chaining
    Write function $ to support method chaining like jQuery.
    example

    $("#button")
      .css("color", "#fff")
      .css("backgroundColor", "#000")
      .css("fontWeight", "bold");
  7. Generate Selectors
    Given a DOM tree and a target element, generate a valid selector to target it.
    Function should take target element into input and return string of valid selector.
    You can use id, class, tag-name etc...
    example

    <div>
      <p>dev</p>
      <div>
        is
        <p>
          <span>
            great. <button>click me!</button>
          </span>
        </p>
      </div>
    </div>
    //Input:- Button Element
    //Output:- body > div > div:nth-child(1) > p > span > button
  8. Circuit Breaker
    We have to implement a function that will halt the operation for X amount of time if it fails for Y count.

    const breaker = circuitBreaker(myFn, 2, 3000);
    //if myFn fail then retry 2 times. if it still fails then halt operation for 3000ms.
    //after 3000ms only we can again call myFn.
    
    breaker().then(console.log).catch(console.log); //assume error so we will try 2 times.
    
    setTimeout(() => {
      breaker().then(console.log).catch(console.log); // It will give time limit error since circuit broke.
    }, 2000);
    
    setTimeout(() => {
      breaker().then(console.log).catch(console.log); //3000ms passed so we can again call it
    }, 4900);
  9. Deep Flatten Object
    Given an nested object which can have any type of object, deep flatten it and return the new object in Javascript.
    example

    //Input
    const obj = {
      A: "12",
      B: 23,
      C: {
        P: 23,
        O: {
          L: 56,
        },
        Q: [{ name: null, value: undefined }, 2],
      },
    };
    //Output
    {
      "A": "12",
      "B": 23,
      "C.O.L": 56,
      "C.P": 23,
      "C.Q.0.name": null,
      "C.Q.0.value": undefined,
      "C.Q.1": 2
    }
  10. clear All Timeouts
    write function clearAllTimeouts which will clear All the set timeouts.

  11. Remove Cycle From Object
    Write a function which will remove cycle from object and returns a modified object.

    const a = { b: 10, c: { d: 20 } };
    a.e = a; //circular dependency.
    //a = { b: 10, c: { d: 20 },e:a }
    //OUTPUT
    // a = { b: 10, c: { d: 20 },e:undefined }
  12. My Promise
    Create MyPromise class that supports normal promise operations and below things.

    • new promise: new MyPromise((resolve, reject) => {})
    • chaining : MyPromise.prototype.then() then handlers should be called asynchronously
    • rejection handler: MyPromise.prototype.catch()
    • static methods: MyPromise.resolve(), MyPromise.reject().
  13. Flatten Array
    function to replicate .flat() method of Array

  14. JSON.stringify
    Polyfill of JSON.stringify method

  15. Custom New
    In javascript we use new keyword to create instance of class. Create instance of class without using new keyword for ES5.

    function SuperHero(name: string) {
      this.name = name;
    }
    const batman = newCreator(SuperHero, "bruce");
    console.log(batman instanceof Superhero); //true
    console.log(batman.name); //bruce
  16. Curry
    Currying is the technique of converting a function that takes N arguments(fixed) into a sequence of functions that each takes a x (x<=N) arguments.
    Implement such function.
    Example

    function multiply(a, b, c) {
      return a * b * c;
    }
    const curriedMultiply = curry(multiply);
    console.log(curriedMultiply(2, 3, 4)); //24
    console.log(curriedMultiply(2)(3)(4)); //24
    console.log(curriedMultiply(2, 3)(4)); //24
    console.log(curriedMultiply(2)(3, 4)); //24
  17. Curry 2
    Same as Curry but now we do not want to restrict on number of arguments.
    Function which we want to curry can have any number of arguments.
    Example

    function multiply(...args: number[]) {
      return args.reduce((acc, curr) => acc * curr, 1);
    }
    
    const curried = curry(multiply);
    console.log(curried(2, 3)); //6
    console.log(curried(2, 3)(2)(2)); //24
    console.log(curried(2, 3)(1, 2)(3)); //36
    console.log(curried(2, 3)(2)(1)(10)(2)); //240