Skip to content

Instantly share code, notes, and snippets.

@victorouse
Last active January 23, 2022 13:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save victorouse/86e423665bd510337f2ff771bfd7717a to your computer and use it in GitHub Desktop.
Save victorouse/86e423665bd510337f2ff771bfd7717a to your computer and use it in GitHub Desktop.
Interview questions
// Write debounce, then debounce a scroll event
function onScrollFunction(arg) {
console.log('scrolling ' + arg);
}
function debounce(fn, wait) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => fn.call(this, ...args), wait)
};
}
const debounced = debounce(onScrollFunction, 1000);
window.addEventListener('scroll', () => debounced(1));
// Given two identical DOM tree structures, A and B, and a node from A, find the corresponding node in B
/*
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Facebook DOM Traversal</title>
</head>
<body>
<div id="rootA">
<div>
<div></div>
</div>
<div></div>
<div>
<div>
<div id="nodeA"></div>
<div></div>
</div>
</div>
</div>
<div id="rootB">
<div>
<div></div>
</div>
<div></div>
<div>
<div>
<div id="nodeB"></div>
<div></div>
</div>
</div>
</div>
</body>
</html>
*/
const rootA = document.getElementById('rootA');
const rootB = document.getElementById('rootB');
const nodeA = document.getElementById('nodeA');
const nodeB = document.getElementById('nodeB');
function getPath(root, node) {
const path = [];
while (node !== root) {
const parent = node.parentElement;
const children = Array.from(parent.children);
const nodeIndex = children.indexOf(node);
path.push(nodeIndex);
node = parent;
}
return path;
}
function getNodeFromPath(node, path) {
const toWalk = [...path];
while (toWalk.length > 0) {
node = node.children[toWalk.pop()];
}
return node;
}
function getSymmetricNode(rootA, rootB, nodeA) {
const pathToNode = getPath(rootA, nodeA);
return getNodeFromPath(rootB, pathToNode);
}
const targetNode = getSymmetricNode(rootA, rootB, nodeA);
console.log(nodeB === targetNode);
/* Create an event emitter that goes like this
* emitter = new Emitter();
*
* Allows you to subscribe to some event
* sub1 = emitter.subscribe('function_name', callback1);
* (you can have multiple callbacks to the same event)
* sub2 = emitter.subscribe('function_name', callback2);
*
* You can emit the event you want with this api
* (you can receive 'n' number of arguments)
* sub1.emit('function_name', foo, bar);
*
* And allows you to release the subscription like this
* (but you should be able to still emit from sub2)
* sub1.release();
*/
class Emitter {
constructor() {
this.events = {};
}
subscribe(eventName, callback) {
// Initialise event handlers if event does not exist yet
if (!this.events[eventName]) {
this.events[eventName] = [];
}
// Add callback function to a list of functions to be
// invoked when this event is emitted
this.events[eventName].push(callback);
// Return a function to remove this function from being
// from the list of functions to be invoked when this
// event is emitted
return {
release: () => {
this.events[eventName] = this.events[eventName]
.filter((eventFunction) => eventFunction !== callback);
}
}
}
emit(eventName, ...parameters) {
if (this.events[eventName]) {
this.events[eventName]
.forEach((eventFunction) => eventFunction(...parameters));
}
}
}
const emitter = new Emitter();
const sub1 = emitter.subscribe('test', (arg) => console.log('sub1', arg));
const sub2 = emitter.subscribe('test', (arg1, arg2) => console.log('sub2', arg1, arg2));
emitter.emit('test', 1);
sub1.release();
emitter.emit('test', 1, 2);
// Given an array of objects, O, and an object of properties, P, write a function that exlcudes the properties from P in O
function createExcludedMap(excludes) {
return excludes.reduce((map, pair) => {
const values = map.get(pair.k);
if (values) {
values.push(pair.v);
return map.set(pair.k, values);
}
return map.set(pair.k, [pair.v]);
}, new Map());
}
/*
function excludeItems(items, excludes) {
excludes.forEach((pair, outer) => {
items = items.filter((item, inner) => {
return item[pair.k] !== pair.v;
});
});
return items;
}
*/
/*
function excludeItems(items, excludes) {
const included = [];
for (const item of items) {
let excluded = false;
for (const [key, values] of excludesMap) {
if (item[key] && values.includes(item[key])) {
excluded = true;
break;
}
}
if (!excluded) {
included.push(item);
}
}
return included;
}
*/
function excludeItems(items, excludes) {
for (const item of items) {
for (const [key, values] of excludesMap) {
items = items.filter((item) => !values.includes(item[key]));
}
}
return items;
}
const items = [
{ color: 'red', type: 'tv', age: 18 },
{ color: 'red', type: 'phone', age: 20 },
{ color: 'silver', type: 'tv', age: 18 },
{ color: 'silver', type: 'phone', age: 20 }
];
const excludes = [
{ k: 'color', v: 'red' },
{ k: 'color', v: 'blue' },
{ k: 'type', v: 'phone' },
];
/*
const excludesMap = new Map(
['color', ['red', 'blue']],
['type', ['phone']]
);
*/
const excludesMap = createExcludedMap(excludes);
console.log('result', excludeItems(items, excludesMap));
// Write array flatten to arbitrary depth, with recursion and without.
/*
Inputs
-------
(1): Empty array
--
[]
=> []
(2): Flattened already
--
[1]
=> [1]
(3): One level deep
--
[[1]]
=> [1]
(4): Mixed with one level deep
--
[1, [2]]
=> [1, 2]
(5): One level deep multiple arrays
--
[[1, 2], [3, 4]]
=> [1, 2, 3, 4]
(6): Two levels deep
--
[[1, [2, 3]], [4, [5, 6, 7]]]
=> [1, 2, 3, 4, 5, 6, 7]
(7): Arbitrary depth
--
[1, [2, [[3]], [4, 5, 6]], [[[[[[7, 8, 9]]]]]]]
=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
*/
function flatten(arr) {
return arr.reduce((flatArray, current) => {
if (Array.isArray(current)) {
return flatArray.concat(flatten(current));
}
flatArray.push(current);
return flatArray;
}, []);
}
function flattenIterative(arr) {
const flatArray = [];
let original = [...arr];
while (original.length > 0) {
const current = original.shift();
if (Array.isArray(current)) {
original = current.concat(original);
} else {
flatArray.push(current);
}
}
return flatArray;
}
const input1 = [];
console.log('result', flatten(input1));
console.log('result', flattenIterative(input1));
const input2 = [1];
console.log('result', flatten(input2));
console.log('result', flattenIterative(input2));
const input3 = [[1]];
console.log('result', flatten(input3));
console.log('result', flattenIterative(input3));
const input4 = [1, [2]];
console.log('result', flatten(input4));
console.log('result', flattenIterative(input4));
const input5 = [[1, 2], [3, 4]];
console.log('result', flatten(input5));
console.log('result', flattenIterative(input5));
const input6 = [[1, [2, 3]], [4, [5, 6, 7]]];
console.log('result', flatten(input6));
console.log('result', flattenIterative(input6));
const input7 = [1, [2, [[3]], [4, 5, 6]], [[[[[[7, 8, 9]]]]]]];
console.log('result', flatten(input7));
console.log('result', flattenIterative(input7));

Q1

What is the difference between debounce and throttle?

When might you use debounce and when might you use throttle?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment