Categories
interview

Items in Container

const getItems = (str, startIndices, endIndices) => {
  let count = 0;
  const arr = Array(str.length);
  arr[0] = 0;
  for (let i = 1; i < str.length; i++) {
    if (str[i] === '*') {
      count++;
      arr[i] = arr[i - 1];
    } else {
      arr[i] = count;
    }
  }
  const ret = Array(startIndices.length);
  for (let i = 0; i < startIndices.length; i++) {
    ret[i] = arr[endIndices[i] - 1] - arr[startIndices[i] - 1];
  }
  return ret;
}

console.log(getItems('|**|*|*', [1, 1], [5, 6])); // [2,3]

Demo

Categories
interview

In-Flight Media

// In-Flight Media

const getMovies = (flightDuration, movieDurations) => {
  const movieTargetDuration = flightDuration - 30;
  const requiredDurations = {};
  var ret = [];
  for (let [key, movieDuration] of Object.entries(movieDurations)) {
    if (movieDuration in requiredDurations) {
      // Found a pair.
      ret.push([requiredDurations[movieDuration], parseInt(key)]);
    }
    requiredDurations[movieTargetDuration - movieDuration] = parseInt(key);
  }

  // Find the pair with the maximum duration movie.
  var maxDuration = -1;
  var maxLoc = -1;
  for (let [key, value] of Object.entries(ret)) {
    var currMax = Math.max(movieDurations[value[0]], movieDurations[value[1]]);
    if (currMax > maxDuration) {
      maxDuration = currMax;
      maxLoc = key;
    }
  }
 
  // If no pair found then return [-1, 1].
  return maxLoc > -1 ? ret[maxLoc] : [-1, 1];
};

console.log(getMovies(90, [1, 10, 25, 35, 60])); // [2,3]

Demo

Categories
interview

Implement Array.prototype.map()

Array.prototype.map = function(mapper, thisArg) {
  const arr = [];

  for (const [key] of Object.entries(this)) {
    arr[key] = mapper.call(thisArg, this[key], key >>> 0, this);
  }

  return arr;
}

const arr = [];
arr[0] = 0;
arr[2] = 2;
arr[3] = 3;
console.log(arr); // [0, undefined, 2, 3]
console.log(arr.map(x => 2 * x)); // [0, undefined, 4, 6]

Demo

Categories
interview

Create Array of size in Js

const arr = Array(3).fill(5);
console.log(arr); // [5, 5, 5]

Demo

Categories
interview

Uglify CSS Class names



/**
 * @returns {string}
 */
function getUniqueClassName() {
  getUniqueClassName.count = getUniqueClassName.count || 1;

  var helper = () => {
    var count = getUniqueClassName.count++;
    var ret = '';
    while (count > 0) {
      var curr = (count - 1) % 52;
      ret = String.fromCharCode((curr < 26) ? 97 /* a */ + curr : 65      /* A */ + (curr - 26)) + ret;
      count = Math.floor((count - 1) / 52);
    }
    return ret;
  }

  return helper();
}

getUniqueClassName.reset = function() {
  getUniqueClassName.count = 0;
}

console.log(getUniqueClassName()); // a
console.log(getUniqueClassName()); // b


Demo

Categories
interview

HTMLElement to Virtual DOM and back

/**
 * @param {HTMLElement} 
 * @return {object} object literal presentation
 */
function virtualize(element) {
  if (element.nodeType === 3)
    return element.textContent;
  const ret = {
    type: element.tagName.toLowerCase(),
    props: {
      children: []
    }
  };
  element.childNodes.forEach(child => ret.props.children.push(virtualize(child)));
  if (ret.props.children.length === 1)
    ret.props.children = ret.props.children[0];
  for (const {
      name,
      value
    } of element.attributes)
    ret.props[name === 'class' ? 'className' : name] = value;
  return ret;
}

/**
 * @param {object} valid object literal presentation
 * @return {HTMLElement} 
 */
function render(obj) {
  if (typeof obj === 'string') return document.createTextNode(obj);
  const {
    type,
    props: {
      children,
      ...attributes
    }
  } = obj;
  const ret = document.createElement(type);
  const childNodes = typeof children === 'string' ? [children] : children;
  childNodes.forEach(childNode => ret.append(render(childNode)));
  for (const [key, val] of Object.entries(attributes)) {
    ret.setAttribute(key === 'className' ? 'class' : key, val)
  }
  return ret;
}

Demo

Categories
interview

Is Element in View

<body onscroll="onscroll()">

  <div style="width: 400px; height:800px; border:1px solid #222;">Scroll Down</div>

  <div id="demo">
    Demo
  </div>

</body>
const isInView = (element) => {
  const {
    top,
    right,
    bottom,
    left
  } = element.getBoundingClientRect();

  return top >= 0 &&
    left >= 0 &&
    right <= (window.innerWidth || document.documentElement.clientWidth) &&
    bottom <= (window.innerHeight || document.documentElemetn.clientHeight);
};

const demo = document.getElementById('demo');

const onscroll = function() {
  console.log(isInView(demo));
};

Demo

Categories
interview

accessKey

<div>Test</div>
const demo = document.getElementById('demo');

 demo.onclick = (e) => {
   console.log(e.target.textContent);
 };
 demo.accessKey = 'w';

 // Alt + W for Windows + Chrome
 // [Control] [Option] + accesskey for Mac
 // Alt + W for Linux + Chrome

Demo

Categories
interview

Serialize / Deserialize

You can do in this in many ways, the following code does this using prefix traversal.

/**
 * @param {Node} root
 * @return {string}
 */
function serialize(root) {
  if(!root) return '_';
  return `${root.val},${serialize(root.left)},${serialize(root.right)}`;
}

/**
 * @param {string} str
 * @return {Node}
 */
function deserialize(str) {
  const q = str.split(',');
  return dfs(q);

 /**
 * @param {string} str
 * @return {Node}
 */
  function dfs(que) {
    if(!que.length) return null;
    const n = que.shift()
;
    if(n !== '_') {
      const node = new Node(n.value)
      node.left = dfs(q);
      node.right = dfs(q);
      return node;
    }
    return null;
  }
}
Categories
interview

DOM Elements as Keys in Object

To store DOM Elements as keys in object without using WeakMap( ), we can do the following:

<div id="root"></div>
<script>
  class NodeStore {
    static key = 'key';

    set(node, value) {
      node.dataset[NodeStore.key] = value;
    }

    get(node) {
      return this.has(node) && node.dataset[NodeStore.key];
    }

    has(node) {
      return NodeStore.key in (node?.dataset || {});
    }
  }

  const nodeStore = new NodeStore();
  const root = document.getElementById('root');
  nodeStore.set(root, 'root value');
  console.log(nodeStore.has(root)); // true
  console.log(nodeStore.get(root)); // 'root value'
</script>

Demo

However the above solution can only support values of type string. To support any type of value we can use the following solution:

<div id="root"></div>
<script>
class NodeStore {
  static key = 'key';
  constructor() {
    this.map = {};
    this.counter = 0;
  }
   /**
   * @param {Node} node
   * @param {any} value
   */
  set(node, value) {
    node[NodeStore.key] = this.counter;
    this.map[this.counter++] = value;
  }
  /**
   * @param {Node} node
   * @return {any}
   */
  get(node) {
     if (this.has(node)) {
       return this.map[node[NodeStore.key]];
     }
     return;
   }
  
  /**
   * @param {Node} node
   * @return {Boolean}
   */
  has(node) {
    return NodeStore.key in node;
  }
}
const nodeStore = new NodeStore();
const root = document.getElementById('root');
nodeStore.set(root, 22);
console.log(nodeStore.has(root)); // true
console.log(nodeStore.get(root)); // 22
</script>

Demo