1 compose
Title Description: implement a compose function
// The usage is as follows: function fn1(x) { return x + 1; } function fn2(x) { return x + 2; } function fn3(x) { return x + 3; } function fn4(x) { return x + 4; } const a = compose(fn1, fn2, fn3, fn4); console.log(a(1)); // 1+4+3+2+1=11 Copy code
The implementation code is as follows:
function compose(...fn) { if (!fn.length) return (v) => v; if (fn.length === 1) return fn[0]; return fn.reduce( (pre, cur) => (...args) => pre(cur(...args)) ); } Copy code
2. SetTimeout simulates the implementation of setinterval (version with clear timer)
Topic Description: setinterval is used to realize cyclic timing call. There may be some problems. Can settimeout be used to solve them
The implementation code is as follows:
function mySettimeout(fn, t) { let timer = null; function interval() { fn(); timer = setTimeout(interval, t); } interval(); return { cancel:()=>{ clearTimeout(timer) } } } // let a=mySettimeout(()=>{ // console.log(111); // },1000) // let b=mySettimeout(() => { // console.log(222) // }, 1000) Copy code
Extension: can we use setinterval simulation to implement settimeout in turn?
const mySetTimeout = (fn, time) => { const timer = setInterval(() => { clearInterval(timer); fn(); }, time); }; // mySetTimeout(()=>{ // console.log(1); // },1000) Copy code
Extended thinking: why use settimeout simulation to implement setinterval? What is the defect of setinterval?
The answer is Baidu itself. In fact, the interviewer asks a lot of questions. The small series will not be launched here
3 publish subscribe mode
Topic Description: implement a publish subscribe mode with the on emit once off method
The implementation code is as follows:
class EventEmitter { constructor() { this.events = {}; } // Implement subscription on(type, callBack) { if (!this.events[type]) { this.events[type] = [callBack]; } else { this.events[type].push(callBack); } } // Delete subscription off(type, callBack) { if (!this.events[type]) return; this.events[type] = this.events[type].filter((item) => { return item !== callBack; }); } // Execute subscription event only once once(type, callBack) { function fn() { callBack(); this.off(type, fn); } this.on(type, fn); } // Trigger event emit(type, ...rest) { this.events[type] && this.events[type].forEach((fn) => fn.apply(this, rest)); } } // Use the following // const event = new EventEmitter(); // const handle = (...rest) => { // console.log(rest); // }; // event.on("click", handle); // event.emit("click", 1, 2, 3, 4); // event.off("click", handle); // event.emit("click", 1, 2); // event.once("dbClick", () => { // console.log(123456); // }); // event.emit("dbClick"); // event.emit("dbClick"); Copy code
4 array de duplication
The implementation code is as follows:
function uniqueArr(arr) { return [...new Set(arr)]; } Copy code
5 array flattening
Title Description: implement a method to turn a multi-dimensional array into a one-dimensional array
The most common recursive versions are as follows:
function flatter(arr) { if (!arr.length) return; return arr.reduce( (pre, cur) => Array.isArray(cur) ? [...pre, ...flatter(cur)] : [...pre, cur], [] ); } // console.log(flatter([1, 2, [1, [2, 3, [4, 5, [6]]]]])); Copy code
Extended thinking: can we implement it with iterative ideas?
The implementation code is as follows:
function flatter(arr) { if (!arr.length) return; while (arr.some((item) => Array.isArray(item))) { arr = [].concat(...arr); } return arr; } // console.log(flatter([1, 2, [1, [2, 3, [4, 5, [6]]]]])); Copy code
6 parasitic combinatorial inheritance
Title Description: implement a js inheritance method that you think is good
The implementation code is as follows:
function Parent(name) { this.name = name; this.say = () => { console.log(111); }; } Parent.prototype.play = () => { console.log(222); }; function Children(name) { Parent.call(this); this.name = name; } Children.prototype = Object.create(Parent.prototype); Children.prototype.constructor = Children; // let child = new Children("111"); // // console.log(child.name); // // child.say(); // // child.play(); Copy code
7. Implement Promise scheduler with parallel restrictions
Title Description: JS implements an asynchronous Scheduler with concurrency constraints, which ensures that there are at most two tasks running at the same time
addTask(1000,"1"); addTask(500,"2"); addTask(300,"3"); addTask(400,"4"); The output order is: 2 3 1 4 Complete execution process of the whole: At the beginning, 1 and 2 tasks are executed 500ms When, task 2 is completed, output 2, and task 3 starts to execute 800ms When, task 3 is completed, output 3, and task 4 begins to execute 1000ms When 1 task is executed, 1 is output, and only 4 tasks are left to execute 1200ms When the task is completed, output 4 Copy code
The implementation code is as follows:
class Scheduler { constructor(limit) { this.queue = []; this.maxCount = limit; this.runCounts = 0; } add(time, order) { const promiseCreator = () => { return new Promise((resolve, reject) => { setTimeout(() => { console.log(order); resolve(); }, time); }); }; this.queue.push(promiseCreator); } taskStart() { for (let i = 0; i < this.maxCount; i++) { this.request(); } } request() { if (!this.queue || !this.queue.length || this.runCounts >= this.maxCount) { return; } this.runCounts++; this.queue .shift()() .then(() => { this.runCounts--; this.request(); }); } } const scheduler = new Scheduler(2); const addTask = (time, order) => { scheduler.add(time, order); }; addTask(1000, "1"); addTask(500, "2"); addTask(300, "3"); addTask(400, "4"); scheduler.taskStart(); Copy code
8 new operator
Title Description: implementation of handwritten new operator
The implementation code is as follows:
function myNew(fn, ...args) { let obj = Object.create(fn.prototype); let res = fn.call(obj, ...args); if (res && (typeof res === "object" || typeof res === "function")) { return res; } return obj; } The usage is as follows: // // function Person(name, age) { // // this.name = name; // // this.age = age; // // } // // Person.prototype.say = function() { // // console.log(this.age); // // }; // // let p1 = myNew(Person, "lihua", 18); // // console.log(p1.name); // // console.log(p1); // // p1.say(); Copy code
9 call apply bind
Title Description: handwritten call apply bind implementation
The implementation code is as follows:
Function.prototype.myCall = function (context, ...args) { if (!context || context === null) { context = window; } // Create a unique key value as the internal method name of our constructed context let fn = Symbol(); context[fn] = this; //this points to the function calling call // Executing the function and returning the result is equivalent to calling itself as the method of the passed in context return context[fn](...args); }; // The principle of apply is the same, except that the second parameter is the passed in array Function.prototype.myApply = function (context, args) { if (!context || context === null) { context = window; } // Create a unique key value as the internal method name of our constructed context let fn = Symbol(); context[fn] = this; // Execute the function and return the result return context[fn](...args); }; //The implementation of bind is a little more complicated because it considers many situations and involves parameter merging (similar to function coritization) Function.prototype.myBind = function (context, ...args) { if (!context || context === null) { context = window; } // Create a unique key value as the internal method name of our constructed context let fn = Symbol(); context[fn] = this; let _this = this; // bind is a little more complicated const result = function (...innerArgs) { // The first case: if the function bound by bind is used as a constructor through the new operator, the incoming this will not be bound, but this will point to the instantiated object // At this time, because of the new operator, this points to the result instance object, and the result inherits from the passed in_ Based on the prototype chain knowledge, the following conclusions can be drawn // this.__proto__ === result.prototype //this instanceof result =>true // this.__proto__.__proto__ === result.prototype.__proto__ === _this.prototype; //this instanceof _this =>true if (this instanceof _this === true) { // At this time, this points to the instance of result, and there is no need to change this point this[fn] = _this; this[fn](...[...args, ...innerArgs]); //Here, the method of es6 is used to make bind support parameter merging delete this[fn]; } else { // If it is only called as an ordinary function, it is very simple. Directly change this point to the incoming context context[fn](...[...args, ...innerArgs]); delete context[fn]; } }; // If you bind a constructor, you need to inherit the constructor prototype properties and methods // How to implement inheritance: use object create result.prototype = Object.create(this.prototype); return result; }; //The usage is as follows // function Person(name, age) { // console.log(name); //' I passed in the parameter name ' // console.log(age); //' I passed in the parameter age ' // console.log(this); // The constructor this points to the instance object // } // //Constructor prototype method // Person.prototype.say = function() { // console.log(123); // } // let obj = { // objName: 'I am the name passed in by obj name', // objAge: 'I'm the age from obj' // } // //Ordinary function // function normalFun(name, age) { // console.log(name); //' I passed in the parameter name ' // console.log(age); //' I passed in the parameter age ' // console.log(this); // The normal function this points to the first parameter of bind, that is, obj in the example // console.log(this.objName); //' I'm name 'from obj // console.log(this.objAge); //' I'm from obj's age ' // } // Call as constructor first // let bindFun = Person.myBind(obj, 'I am the name passed in by the parameter') // Let a = new bindfund ('I am the age passed in by the parameter ') // a.say() //123 // Retest as a normal function call // let bindFun = normalFun.myBind(obj, 'I am the name passed in by the parameter') // Bindfund ('I am the age passed in by the parameter ') Copy code
10 deep copy (considering replication Symbol type)
Title Description: implementation of handwritten new operator
The implementation code is as follows:
function isObject(val) { return typeof val === "object" && val !== null; } function deepClone(obj, hash = new WeakMap()) { if (!isObject(obj)) return obj; if (hash.has(obj)) { return hash.get(obj); } let target = Array.isArray(obj) ? [] : {}; hash.set(obj, target); Reflect.ownKeys(obj).forEach((item) => { if (isObject(obj[item])) { target[item] = deepClone(obj[item], hash); } else { target[item] = obj[item]; } }); return target; } // var obj1 = { // a:1, // b:{a:2} // }; // var obj2 = deepClone(obj1); // console.log(obj1); Copy code
11 instanceof
Title Description: implementation of handwritten instanceof operator
The implementation code is as follows:
function myInstanceof(left, right) { while (true) { if (left === null) { return false; } if (left.__proto__ === right.prototype) { return true; } left = left.__proto__; } } Copy code
12 coritization
Topic Description: Currying, also known as Partial Evaluation, is a technology that transforms a function that accepts multiple parameters into a function that accepts a single parameter (the first parameter of the original function), and returns a new function that accepts the remaining parameters and returns the result. The core idea is to divide the function passed in by multiple parameters into single parameter (or part) functions, and then call the next single parameter (or part) function to process the remaining parameters in turn.
The implementation code is as follows:
function currying(fn, ...args) { const length = fn.length; let allArgs = [...args]; const res = (...newArgs) => { allArgs = [...allArgs, ...newArgs]; if (allArgs.length === length) { return fn(...allArgs); } else { return res; } }; return res; } // The usage is as follows: // const add = (a, b, c) => a + b + c; // const a = currying(add, 1); // console.log(a(2,3)) Copy code
13 bubble sort -- time complexity n^2
Title Description: realize a bubble sorting
The implementation code is as follows:
function bubbleSort(arr) { // Cache array length const len = arr.length; // The outer loop is used to control how many rounds of comparison + exchange from beginning to end for (let i = 0; i < len; i++) { // The inner loop is used to complete the repeated comparison + exchange in each round of traversal for (let j = 0; j < len - 1; j++) { // If the number in front of adjacent elements is greater than that in the back if (arr[j] > arr[j + 1]) { // Exchange both [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]; } } } // Return array return arr; } // console.log(bubbleSort([3, 6, 2, 4, 1])); Copy code
14 select sort -- time complexity n^2
Title Description: realize a selection sorting
The implementation code is as follows:
function selectSort(arr) { // Cache array length const len = arr.length; // Define minIndex to cache the index of the minimum value of the current interval. Note the index let minIndex; // i is the starting point of the current sorting interval for (let i = 0; i < len - 1; i++) { // Initialize minIndex as the first element of the current interval minIndex = i; // i. J defines the upper and lower bounds of the current interval respectively. I is the left boundary and j is the right boundary for (let j = i; j < len; j++) { // If the data item at j is smaller than the current minimum value, the minimum value index is updated to j if (arr[j] < arr[minIndex]) { minIndex = j; } } // If the corresponding element of minIndex is not the current header element, exchange the two if (minIndex !== i) { [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]]; } } return arr; } // console.log(quickSort([3, 6, 2, 4, 1])); Copy code
15 insert sort -- time complexity n^2
Title Description: implement an insertion sort
The implementation code is as follows:
function insertSort(arr) { for (let i = 1; i < arr.length; i++) { let j = i; let target = arr[j]; while (j > 0 && arr[j - 1] > target) { arr[j] = arr[j - 1]; j--; } arr[j] = target; } return arr; } // console.log(insertSort([3, 6, 2, 4, 1])); Copy code
Complexity between n ^ 16 and n ^ 2
Title Description: realize a fast scheduling
The implementation code is as follows:
function quickSort(arr) { if (arr.length < 2) { return arr; } const cur = arr[arr.length - 1]; const left = arr.filter((v, i) => v <= cur && i !== arr.length - 1); const right = arr.filter((v) => v > cur); return [...quickSort(left), cur, ...quickSort(right)]; } // console.log(quickSort([3, 6, 2, 4, 1])); Copy code
17 merge sort -- time complexity nlog(n)
Title Description: implement a sorting algorithm with time complexity of nlog(n)
The implementation code is as follows:
function merge(left, right) { let res = []; let i = 0; let j = 0; while (i < left.length && j < right.length) { if (left[i] < right[j]) { res.push(left[i]); i++; } else { res.push(right[j]); j++; } } if (i < left.length) { res.push(...left.slice(i)); } else { res.push(...right.slice(j)); } return res; } function mergeSort(arr) { if (arr.length < 2) { return arr; } const mid = Math.floor(arr.length / 2); const left = mergeSort(arr.slice(0, mid)); const right = mergeSort(arr.slice(mid)); return merge(left, right); } // console.log(mergeSort([3, 6, 2, 4, 1])); Copy code
18 binary search -- time complexity log2(n)
Topic Description: how to determine the position of a number in an ordered array
The implementation code is as follows:
function search(arr, target, start, end) { let targetIndex = -1; let mid = Math.floor((start + end) / 2); if (arr[mid] === target) { targetIndex = mid; return targetIndex; } if (start >= end) { return targetIndex; } if (arr[mid] < target) { return search(arr, target, mid + 1, end); } else { return search(arr, target, start, mid - 1); } } // const dataArr = [1, 2, 3, 4, 5, 6, 7, 8, 9]; // const position = search(dataArr, 6, 0, dataArr.length - 1); // if (position !== -1) { // console.log(` position of the target element in the array: ${position} `); // } else { // console.log("the target element is not in the array"); // } Copy code
19 implementation of LazyMan
Title Description:
Implement a LazyMan,Can be called as follows: LazyMan("Hank")output: Hi! This is Hank! LazyMan("Hank").sleep(10).eat("dinner")output Hi! This is Hank! //Wait 10 seconds Wake up after 10 Eat dinner~ LazyMan("Hank").eat("dinner").eat("supper")output Hi This is Hank! Eat dinner~ Eat supper~ LazyMan("Hank").eat("supper").sleepFirst(5)output //Wait 5 seconds Wake up after 5 Hi This is Hank! Eat supper Copy code
The implementation code is as follows:
class _LazyMan { constructor(name) { this.tasks = []; const task = () => { console.log(`Hi! This is ${name}`); this.next(); }; this.tasks.push(task); setTimeout(() => { // Put this Next () is executed after the call stack is cleared this.next(); }, 0); } next() { const task = this.tasks.shift(); // Take the first task to execute task && task(); } sleep(time) { this._sleepWrapper(time, false); return this; // call chaining } sleepFirst(time) { this._sleepWrapper(time, true); return this; } _sleepWrapper(time, first) { const task = () => { setTimeout(() => { console.log(`Wake up after ${time}`); this.next(); }, time * 1000); }; if (first) { this.tasks.unshift(task); // Put at the top of the task queue } else { this.tasks.push(task); // Put at the end of the task queue } } eat(name) { const task = () => { console.log(`Eat ${name}`); this.next(); }; this.tasks.push(task); return this; } } function LazyMan(name) { return new _LazyMan(name); } Copy code
20 anti shake throttle
Title Description: handwritten anti shake throttle
The implementation code is as follows:
// Anti shake function debounce(fn, delay = 300) { //Default 300 ms let timer; return function () { const args = arguments; if (timer) { clearTimeout(timer); } timer = setTimeout(() => { fn.apply(this, args); // Change this to point to the object that debounce refers to }, delay); }; } window.addEventListener( "scroll", debounce(() => { console.log(111); }, 1000) ); // throttle // Set a flag function throttle(fn, delay) { let flag = true; return () => { if (!flag) return; flag = false; timer = setTimeout(() => { fn(); flag = true; }, delay); }; } window.addEventListener( "scroll", throttle(() => { console.log(111); }, 1000) ); Copy code
21 write version number sorting method
Title Description: there is a set of version numbers as follows ['0.1.1', '2.3.3', '0.302.1', '4.2', '4.3.5', '4.3.4.5']. Now you need to sort them. The sorting results are ['4.3.5', '4.3.4.5', '2.3.3', '0.302.1', '0.1.1']
The implementation code is as follows:
arr.sort((a, b) => { let i = 0; const arr1 = a.split("."); const arr2 = b.split("."); while (true) { const s1 = arr1[i]; const s2 = arr2[i]; i++; if (s1 === undefined || s2 === undefined) { return arr2.length - arr1.length; } if (s1 === s2) continue; return s2 - s1; } }); console.log(arr); Copy code
22 LRU algorithm
Title Description:
The implementation code is as follows:
// A Map object will be iterated according to the insertion order of elements in the object // The newly added element will be inserted at the end of the map, and the whole stack will be viewed in reverse order class LRUCache { constructor(capacity) { this.secretKey = new Map(); this.capacity = capacity; } get(key) { if (this.secretKey.has(key)) { let tempValue = this.secretKey.get(key); this.secretKey.delete(key); this.secretKey.set(key, tempValue); return tempValue; } else return -1; } put(key, value) { // key exists, only modify the value if (this.secretKey.has(key)) { this.secretKey.delete(key); this.secretKey.set(key, value); } // key does not exist, cache is not full else if (this.secretKey.size < this.capacity) { this.secretKey.set(key, value); } // Add new key and delete old key else { this.secretKey.set(key, value); // Delete the first element of the map, which is the longest unused element this.secretKey.delete(this.secretKey.keys().next().value); } } } // let cache = new LRUCache(2); // cache.put(1, 1); // cache.put(2, 2); // console.log("cache.get(1)", cache.get(1)) / / returns 1 // cache.put(3, 3);// This operation will invalidate key 2 // console.log("cache.get(2)", cache.get(2)) / / returns - 1 (not found) // cache.put(4, 4);// This operation will invalidate key 1 // console.log("cache.get(1)", cache.get(1)) / / return - 1 (not found) // console.log("cache.get(3)", cache.get(3)) / / returns 3 // console.log("cache.get(4)", cache.get(4)) / / returns 4 Copy code
23 Promise and implementation of related methods
Title Description: handwritten promise and promise all Promise. Implementation of race
The implementation code is as follows:
class Mypromise { constructor(fn) { // Indicates the status this.state = "pending"; // Indicates the successful function of then registration this.successFun = []; // A function that represents the failure of then registration this.failFun = []; let resolve = (val) => { // Keep the state change immutable (only one of resolve and reject can be triggered) if (this.state !== "pending") return; // Successfully trigger the opportunity to change the state and execute the callback event registered in then this.state = "success"; // In order to ensure that the then event is registered first (mainly considering writing synchronous code in promise), the promise specification here is to simulate asynchronous setTimeout(() => { // Execute all registration functions in the current event this.successFun.forEach((item) => item.call(this, val)); }); }; let reject = (err) => { if (this.state !== "pending") return; // Failure triggers the opportunity to change the state and execute the callback event registered in then this.state = "fail"; // In order to ensure that the then event is registered first (mainly considering writing synchronous code in promise), the promise specification simulates asynchronous setTimeout(() => { this.failFun.forEach((item) => item.call(this, err)); }); }; // Call function try { fn(resolve, reject); } catch (error) { reject(error); } } // Instance method then then(resolveCallback, rejectCallback) { // Determine whether the callback is a function resolveCallback = typeof resolveCallback !== "function" ? (v) => v : resolveCallback; rejectCallback = typeof rejectCallback !== "function" ? (err) => { throw err; } : rejectCallback; // In order to keep the chained call, continue to return promise return new Mypromise((resolve, reject) => { // Register the callback in the successFun event collection this.successFun.push((val) => { try { // Execute callback function let x = resolveCallback(val); //(the hardest point) // If the result of the callback function is a normal value, then resolve will be sent out to the next then chain call. If it is a promise object (representing another asynchronous), then call the then method of X to pass in resolve and reject. When the asynchronous execution inside x is completed (the state is completed), the incoming resolve will be automatically executed, which controls the sequence of chain calls x instanceof Mypromise ? x.then(resolve, reject) : resolve(x); } catch (error) { reject(error); } }); this.failFun.push((val) => { try { // Execute callback function let x = rejectCallback(val); x instanceof Mypromise ? x.then(resolve, reject) : reject(x); } catch (error) { reject(error); } }); }); } //Static method static all(promiseArr) { let result = []; //Declare a counter and add one for each promise return let count = 0; return new Mypromise((resolve, reject) => { for (let i = 0; i < promiseArr.length; i++) { //Promise Resolve is wrapped to prevent non promise types from being passed in Promise.resolve(promiseArr[i]).then( (res) => { //You can't directly push the array here, because you want to control the order one-to-one correspondence (thanks for pointing in the comment area) result[i] = res; count++; //resolve will not be released until all promise s are successfully executed if (count === promiseArr.length) { resolve(result); } }, (err) => { reject(err); } ); } }); } //Static method static race(promiseArr) { return new Mypromise((resolve, reject) => { for (let i = 0; i < promiseArr.length; i++) { Promise.resolve(promiseArr[i]).then( (res) => { //Promise array can be returned as long as there is any promise state change resolve(res); }, (err) => { reject(err); } ); } }); } } // use // let promise1 = new Mypromise((resolve, reject) => { // setTimeout(() => { // resolve(123); // }, 2000); // }); // let promise2 = new Mypromise((resolve, reject) => { // setTimeout(() => { // resolve(1234); // }, 1000); // }); // Mypromise.all([promise1,promise2]).then(res=>{ // console.log(res); // }) // Mypromise.race([promise1, promise2]).then(res => { // console.log(res); // }); // promise1 // .then( // res => { // console.log(res); // Output 123 in two seconds // return new Mypromise((resolve, reject) => { // setTimeout(() => { // resolve("success"); // }, 1000); // }); // }, // err => { // console.log(err); // } // ) // .then( // res => { // console.log(res); // Output success in another second // }, // err => { // console.log(err); // } // ); Copy code
Extended thinking: how to cancel promise
Promise. Promise () can be used to compete with its own empty wrapper
function wrap(pro) { let obj = {}; // Construct a new promise to compete let p1 = new Promise((resolve, reject) => { obj.resolve = resolve; obj.reject = reject; }); obj.promise = Promise.race([p1, pro]); return obj; } let testPro = new Promise((resolve, reject) => { setTimeout(() => { resolve(123); }, 1000); }); let wrapPro = wrap(testPro); wrapPro.promise.then((res) => { console.log(res); }); wrapPro.resolve("Intercepted"); Copy code
24 implement an add method
Title Description: implement an add method to make the calculation result meet the following expectations: add(1)(2)(3)()=6 add(1,2,3)(4)()=10
In fact, it is Cauchy function
The implementation code is as follows:
function add(...args) { let allArgs = [...args]; function fn(...newArgs) { allArgs = [...allArgs, ...newArgs]; return fn; } fn.toString = function () { if (!allArgs.length) { return; } return allArgs.reduce((sum, cur) => sum + cur); }; return fn; } Copy code
Solving coin change problem by dynamic programming
Title Description: give coins of different denominations coins and a total amount. Write a function to calculate the minimum number of coins needed to make up the total amount. If no coin combination can form a total amount, return - 1
Example 1: input: coins = [1, 2, 5], amount = 11 output: 3 explain: 11 = 5 + 5 + 1 Example 2: input: coins = [2], amount = 3 output: -1 Copy code
The implementation code is as follows:
const coinChange = function (coins, amount) { // Used to save the minimum number of coins corresponding to each target total const f = []; // Define known situations in advance f[0] = 0; // Traverse the total amount of coins in the interval [1, amount] for (let i = 1; i <= amount; i++) { // It is the minimum value, so we preset it to infinity to ensure that it will be updated by a smaller number f[i] = Infinity; // Loop through the denomination of each available coin for (let j = 0; j < coins.length; j++) { // If the coin denomination is less than the target total, the problem is established if (i - coins[j] >= 0) { // State transition equation f[i] = Math.min(f[i], f[i - coins[j]] + 1); } } } // If the solution corresponding to the target total amount is infinite, it means that there is no qualified total number of coins to update it. This problem has no solution and returns - 1 if (f[amount] === Infinity) { return -1; } // If there is a solution, directly return the content of the solution return f[amount]; }; Copy code
Please implement a function of DOM2JSON, which can output a DOM node in JSON format
Title Description:
<div> <span> <a></a> </span> <span> <a></a> <a></a> </span> </div> Appeal dom The structure is transformed into the following JSON format { tag: 'DIV', children: [ { tag: 'SPAN', children: [ { tag: 'A', children: [] } ] }, { tag: 'SPAN', children: [ { tag: 'A', children: [] }, { tag: 'A', children: [] } ] } ] } Copy code
The implementation code is as follows:
function dom2Json(domtree) { let obj = {}; obj.name = domtree.tagName; obj.children = []; domtree.childNodes.forEach((child) => obj.children.push(dom2Json(child))); return obj; } Copy code
Extended thinking: how to parse a given html string instead of a Dom tree structure?
Then this problem is similar to Vue's template compilation principle. We can use regular matching html string to generate the corresponding ast after encountering the start tag, end tag and text parsing, establish the corresponding parent-child Association, and constantly intercept the remaining strings until all html is parsed. Those interested can see it here
Method for converting class 27 array into array
Topic Description: class arrays have the length attribute. You can use subscripts to access elements, but you can't use array methods. How to convert class arrays into arrays?
The implementation code is as follows:
const arrayLike=document.querySelectorAll('div') // 1. Extension operator [...arrayLike] // 2.Array.from Array.from(arrayLike) // 3.Array.prototype.slice Array.prototype.slice.call(arrayLike) // 4.Array.apply Array.apply(null, arrayLike) // 5.Array.prototype.concat Array.prototype.concat.apply([], arrayLike) Copy code
28 Object.is implementation
Title Description:
Object.is The types of the two values being compared are not converted, and===More similar, there are some differences between them. 1. NaN stay===Is not equal in, and in Object.is Are equal in 2. +0 and-0 stay===Is equal in, and in Object.is Are not equal Copy code
The implementation code is as follows:
Object.is = function (x, y) { if (x === y) { // In the current case, only one case is special, that is + 0 - 0 // If x== 0, returns true // If x === 0, you need to judge + 0 and - 0. You can directly use 1/+0 === Infinity and 1/-0 === -Infinity to judge return x !== 0 || 1 / x === 1 / y; } // x !== In the case of Y, you only need to judge whether it is NaN, if x== x. Then x is NaN, and so is y // Returns true when x and y are both NaN return x !== x && y !== y; }; Copy code
29 AJAX
Title Description: handwritten AJAX implementation using XMLHttpRequest
The implementation code is as follows:
const getJSON = function (url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open("GET", url, false); xhr.setRequestHeader("Content-Type", "application/json"); xhr.onreadystatechange = function () { if (xhr.readyState !== 4) return; if (xhr.status === 200 || xhr.status === 304) { resolve(xhr.responseText); } else { reject(new Error(xhr.responseText)); } }; xhr.send(); }); }; Copy code
30 slice idea to solve the problem of large amount of data rendering
Title Description: how to use the idea of fragmentation to optimize rendering when rendering millions of pieces of big data with simple structure
The implementation code is as follows:
let ul = document.getElementById("container"); // Insert 100000 pieces of data let total = 100000; // Insert 20 at a time let once = 20; //PageCount let page = total / once; //Index of each record let index = 0; //Cyclic loading data function loop(curTotal, curIndex) { if (curTotal <= 0) { return false; } //How many entries per page let pageCount = Math.min(curTotal, once); window.requestAnimationFrame(function () { for (let i = 0; i < pageCount; i++) { let li = document.createElement("li"); li.innerText = curIndex + i + " : " + ~~(Math.random() * total); ul.appendChild(li); } loop(curTotal - pageCount, curIndex + pageCount); }); } loop(total, index); Copy code
Extended thinking: for simple dom structure rendering with large amount of data, the idea of fragmentation can be used. How to deal with complex dom structure rendering?
At this time, we need to use the virtual list. Baidu ha virtual list and virtual table are still used frequently in daily projects
31 convert virtual Dom to real Dom
Title Description: how to convert a virtual Dom in JSON format into a real Dom
{ tag: 'DIV', attrs:{ id:'app' }, children: [ { tag: 'SPAN', children: [ { tag: 'A', children: [] } ] }, { tag: 'SPAN', children: [ { tag: 'A', children: [] }, { tag: 'A', children: [] } ] } ] } Virtual appeal Dom Convert to reality below Dom <div id="app"> <span> <a></a> </span> <span> <a></a> <a></a> </span> </div> Copy code
The implementation code is as follows:
// Real rendering function function _render(vnode) { // If it is a numeric type, convert it to a string if (typeof vnode === "number") { vnode = String(vnode); } // The string type is the text node directly if (typeof vnode === "string") { return document.createTextNode(vnode); } // Normal DOM const dom = document.createElement(vnode.tag); if (vnode.attrs) { // traversal attributes Object.keys(vnode.attrs).forEach((key) => { const value = vnode.attrs[key]; dom.setAttribute(key, value); }); } // Recursive operation of subarray vnode.children.forEach((child) => dom.appendChild(_render(child))); return dom; } Copy code
32 realize the template string parsing function
Title Description:
let template = 'I am{{name}},Age{{age}},Gender{{sex}}'; let data = { name: 'full name', age: 18 } render(template, data); // My name is, age 18, gender undefined Copy code
The implementation code is as follows:
function render(template, data) { let computed = template.replace(/\{\{(\w+)\}\}/g, function (match, key) { return data[key]; }); return computed; } Copy code
33 implement the flatten method of an object
Title Description:
const obj = { a: { b: 1, c: 2, d: {e: 5} }, b: [1, 3, {a: 2, b: 3}], c: 3 } flatten(obj) The results are returned as follows // { // 'a.b': 1, // 'a.c': 2, // 'a.d.e': 5, // 'b[0]': 1, // 'b[1]': 3, // 'b[2].a': 2, // 'b[2].b': 3 // c: 3 // } Copy code
The implementation code is as follows:
function isObject(val) { return typeof val === "object" && val !== null; } function flatten(obj) { if (!isObject(obj)) { return; } let res = {}; const dfs = (cur, prefix) => { if (isObject(cur)) { if (Array.isArray(cur)) { cur.forEach((item, index) => { dfs(item, `${prefix}[${index}]`); }); } else { for (let k in cur) { dfs(cur[k], `${prefix}${prefix ? "." : ""}${k}`); } } } else { res[prefix] = cur; } }; dfs(obj, ""); return res; } flatten(); Copy code
34 convert list to tree structure
Title Description:
[ { id: 1, text: 'Node 1', parentId: 0 //Here, 0 is represented as the top-level node }, { id: 2, text: 'Node 1_1', parentId: 1 //This field determines the child parent } ... ] Turn into [ { id: 1, text: 'Node 1', parentId: 0, children: [ { id:2, text: 'Node 1_1', parentId:1 } ] } ] Copy code
The implementation code is as follows:
function listToTree(data) { let temp = {}; let treeData = []; for (let i = 0; i < data.length; i++) { temp[data[i].id] = data[i]; } for (let i in temp) { if (+temp[i].parentId != 0) { if (!temp[temp[i].parentId].children) { temp[temp[i].parentId].children = []; } temp[temp[i].parentId].children.push(temp[i]); } else { treeData.push(temp[i]); } } return treeData; } Copy code
35 convert tree structure to list
Title Description:
[ { id: 1, text: 'Node 1', parentId: 0, children: [ { id:2, text: 'Node 1_1', parentId:1 } ] } ] Turn into [ { id: 1, text: 'Node 1', parentId: 0 //Here, 0 is represented as the top-level node }, { id: 2, text: 'Node 1_1', parentId: 1 //This field determines the child parent } ... ] Copy code
The implementation code is as follows:
function treeToList(data) { let res = []; const dfs = (tree) => { tree.forEach((item) => { if (item.children) { dfs(item.children); delete item.children; } res.push(item); }); }; dfs(data); return res; } Copy code
36 addition of large numbers
Title Description: implement an add method to complete the addition of two large numbers
let a = "9007199254740991"; let b = "1234567899999999999"; function add(a ,b){ //... } Copy code
The implementation code is as follows:
function add(a ,b){ //Take the maximum length of two numbers let maxLength = Math.max(a.length, b.length); //Use 0 to supplement the length a = a.padStart(maxLength , 0);//"0009007199254740991" b = b.padStart(maxLength , 0);//"1234567899999999999" //Define the variables needed in the addition process let t = 0; let f = 0; //"Carry" let sum = ""; for(let i=maxLength-1 ; i>=0 ; i--){ t = parseInt(a[i]) + parseInt(b[i]) + f; f = Math.floor(t/10); sum = t%10 + sum; } if(f!==0){ sum = '' + f + sum; } return sum; }