Please implement DOM2JSON, a function that can output a DOM node in JSON format
<div> <span> <a></a> </span> <span> <a></a> <a></a> </span> </div> put the top dom structure into the following JSON Format { tag: 'DIV', children: [ { tag: 'SPAN', children: [ { tag: 'A', children: [] } ] }, { tag: 'SPAN', children: [ { tag: 'A', children: [] }, { tag: 'A', children: [] } ] } ] }
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; }
Convert to camelCase
var s1 = "get-element-by-id" // Convert to getElementById var f = function(s) { return s.replace(/-\w/g, function(x) { return x.slice(1).toUpperCase(); }) }
Modify the key of a deeply nested object
// There is an object with a deep nesting level, and the key s are all in the form of a_b, which needs to be changed to the form of ab. Note that recursion cannot be used. const a = { a_y: { a_z: { y_x: 6 }, b_c: 1 } } // { // ay: { // az: { // yx: 6 // }, // bc: 1 // } // }
Method 1: Serialize JSON.stringify + regular matching
const regularExpress = (obj) => { try { const str = JSON.stringify(obj).replace(/_/g, ""); return JSON.parse(str); } catch (error) { return obj; } };;
Method 2: Recursive
const recursion = (obj) => { const keys = Object.keys(obj); keys.forEach((key) => { const newKey = key.replace(/_/g, ""); obj[newKey] = recursion(obj[key]); delete obj[key]; }); return obj; };
Summary of reduce usage
grammar
array.reduce(function(total, currentValue, currentIndex, arr), initialValue); /* total: required. The initial value, or the return value after the calculation is completed. currentValue: required. the current element. currentIndex: optional. the index of the current element; arr: optional. The array object to which the current element belongs. initialValue: optional. The initial value passed to the function is equivalent to the initial value of total. */
reduceRight() This method is actually the same as reduce(), except that the order of traversal is reversed, starting from the last item in the array and traversing forward to the first item
1. Array sum
const arr = [12, 34, 23]; const sum = arr.reduce((total, num) => total + num); // Set the initial value to sum const arr = [12, 34, 23]; const sum = arr.reduce((total, num) => total + num, 10); // Summing with 10 as the initial value // sum array of objects var result = [ { subject: 'math', score: 88 }, { subject: 'chinese', score: 95 }, { subject: 'english', score: 80 } ]; const sum = result.reduce((accumulator, cur) => accumulator + cur.score, 0); const sum = result.reduce((accumulator, cur) => accumulator + cur.score, -10); // 10 points will be deducted from the total score
2. The maximum value of the array
const a = [23,123,342,12]; const max = a.reduce((pre,next)=>pre>cur?pre:cur,0); // 342
3. Array to object
var streams = [{name: 'technology', id: 1}, {name: 'design', id: 2}]; var obj = streams.reduce((accumulator, cur) => {accumulator[cur.id] = cur; return accumulator;}, {});
4. Flatten a two-dimensional array
var arr = [[1, 2, 8], [3, 4, 9], [5, 6, 10]]; var res = arr.reduce((x, y) => x.concat(y), []);
5. Array deduplication
The basic principle of implementation is as follows: ① initialize an empty array ② Find the first item in the array that needs to be deduplicated in the initialization array, if it cannot be found (it must not be found in the empty array), add the item to the initialization array ③ Find the second item in the array that needs to be deduplicated in the initialization array, if not found, continue to add the item to the initialization array ④ ...... ⑤ The first in the array that needs to be deduplicated n The item is searched in the initialization array, if not found, the item is added to the initialization array ⑥ Return this initialized array
var newArr = arr.reduce(function (prev, cur) { prev.indexOf(cur) === -1 && prev.push(cur); return prev; },[]);
6. Object array deduplication
const dedup = (data, getKey = () => { }) => { const dateMap = data.reduce((pre, cur) => { const key = getKey(cur) if (!pre[key]) { pre[key] = cur } return pre }, {}) return Object.values(dateMap) }
7. Find the number of occurrences of letters in a string
const str = 'sfhjasfjgfasjuwqrqadqeiqsajsdaiwqdaklldflas-cmxzmnha'; const res = str.split('').reduce((pre,next)=>{ pre[next] ? pre[next]++ : pre[next] = 1 return pre },{})
// result -: 1 a: 8 c: 1 d: 4 e: 1 f: 4 g: 1 h: 2 i: 2 j: 4 k: 1 l: 3 m: 2 n: 1 q: 5 r: 1 s: 6 u: 1 w: 2 x: 1 z: 1
8. compose function
redux compose source code implementation
function compose(...funs) { if (funs.length === 0) { return arg => arg; } if (funs.length === 1) { return funs[0]; } return funs.reduce((a, b) => (...arg) => a(b(...arg))) }
Convert object array list into tree structure (processing menu)
[ { id: 1, text: 'node 1', parentId: 0 //0 is used here as the top-level node }, { id: 2, text: 'node 1_1', parentId: 1 //Use this field to determine the child parent } ... ] Turn into [ { id: 1, text: 'node 1', parentId: 0, children: [ { id:2, text: 'node 1_1', parentId:1 } ] } ]
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; }
How to generate a non-repetitive random array of length n in the specified data source? There are several methods. What is the time complexity (bytes)
The first version has a time complexity of O(n^2)
function getTenNum(testArray, n) { let result = []; for (let i = 0; i < n; ++i) { const random = Math.floor(Math.random() * testArray.length); const cur = testArray[random]; if (result.includes(cur)) { i--; break; } result.push(cur); } return result; } const testArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]; const resArr = getTenNum(testArray, 10);
Version 2 Notation method / custom attribute method Time complexity is O(n)
function getTenNum(testArray, n) { let hash = {}; let result = []; let ranNum = n; while (ranNum > 0) { const ran = Math.floor(Math.random() * testArray.length); if (!hash[ran]) { hash[ran] = true; result.push(ran); ranNum--; } } return result; } const testArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]; const resArr = getTenNum(testArray, 10);
The third version of the exchange method has a time complexity of O(n)
function getTenNum(testArray, n) { const cloneArr = [...testArray]; let result = []; for (let i = 0; i < n; i++) { debugger; const ran = Math.floor(Math.random() * (cloneArr.length - i)); result.push(cloneArr[ran]); cloneArr[ran] = cloneArr[cloneArr.length - i - 1]; } return result; } const testArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]; const resArr = getTenNum(testArray, 14);
It is worth mentioning that the exchange method is used when manipulating arrays. This idea is very common in algorithms.
The final version deletes while traversing, and the time complexity is O(n)
function getTenNum(testArray, n) { const cloneArr = [...testArray]; let result = []; for (let i = 0; i < n; ++i) { const random = Math.floor(Math.random() * cloneArr.length); const cur = cloneArr[random]; result.push(cur); cloneArr.splice(random, 1); } return result; } const testArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]; const resArr = getTenNum(testArray, 14);
refer to Detailed answers to front-end advanced interview questions
Determine whether the bracket string is valid (Xiaomi)
topic description
Given a given only '(',')','{','}','[',']' String s ,Determines whether a string is valid. A valid string must satisfy: - An opening parenthesis must be closed with a closing parenthesis of the same type. - Opening parentheses must be closed in the correct order. Example 1: enter: s = "()" output: true Example 2: enter: s = "()[]{}" output: true Example 3: enter: s = "(]" output: false
Answer
const isValid = function (s) { if (s.length % 2 === 1) { return false; } const regObj = { "{": "}", "(": ")", "[": "]", }; let stack = []; for (let i = 0; i < s.length; i++) { if (s[i] === "{" || s[i] === "(" || s[i] === "[") { stack.push(s[i]); } else { const cur = stack.pop(); if (s[i] !== regObj[cur]) { return false; } } } if (stack.length) { return false; } return true; };
Implements a Promise scheduler with parallel constraints
Title description: JS implements an asynchronous scheduler Scheduler with concurrency restrictions, ensuring 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 The entire complete execution process: At the beginning, the two tasks 1 and 2 start to execute 500ms When , task 2 is executed, output 2, and task 3 starts to execute 800ms When , task 3 is executed, output 3, and task 4 starts to execute 1000ms When 1 task is executed, 1 is output, and only 4 tasks are left to execute 1200ms When , 4 tasks are executed, output 4
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();
implement a queue
Queue based on linked list structure
const LinkedList = require('./Implement a linked list structure') // Use linked lists to simulate queues by default using arrays for better performance class Queue { constructor() { this.ll = new LinkedList() } // add to queue offer(elem) { this.ll.add(elem) } // view the first peek() { return this.ll.get(0) } // Queues can only be removed from the head remove() { return this.ll.remove(0) } } var queue = new Queue() queue.offer(1) queue.offer(2) queue.offer(3) var removeVal = queue.remove(3) console.log(queue.ll,'queue.ll') console.log(removeVal,'queue.remove') console.log(queue.peek(),'queue.peek')
Convert tree structure to list (processing menu)
[ { 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 //0 is used here as the top-level node }, { id: 2, text: 'node 1_1', parentId: 1 //Use this field to determine the child parent } ... ]
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; }
Implement thousands separator
// three decimal places parseToMoney(1234.56); // return '1,234.56' parseToMoney(123456789); // return '123,456,789' parseToMoney(1087654.321); // return '1,087,654.321'
function parseToMoney(num) { num = parseFloat(num.toFixed(3)); let [integer, decimal] = String.prototype.split.call(num, '.'); integer = integer.replace(/\d(?=(\d{3})+$)/g, '$&,'); return integer + '.' + (decimal ? decimal : ''); }
The longest non-repeating substring of a string
topic description
given a string s ,Please find the length of the longest substring that does not contain repeated characters. Example 1: enter: s = "abcabcbb" output: 3 explain: Since the longest substring without repeating characters is "abc",So its length is 3. Example 2: enter: s = "bbbbb" output: 1 explain: Since the longest substring without repeating characters is "b",So its length is 1. Example 3: enter: s = "pwwkew" output: 3 explain: Since the longest substring without repeating characters is "wke",So its length is 3. Note that your answer must be the length of the substring,"pwke" is a subsequence, not a substring. Example 4: enter: s = "" output: 0
Answer
const lengthOfLongestSubstring = function (s) { if (s.length === 0) { return 0; } let left = 0; let right = 1; let max = 0; while (right <= s.length) { let lr = s.slice(left, right); const index = lr.indexOf(s[right]); if (index > -1) { left = index + left + 1; } else { lr = s.slice(left, right + 1); max = Math.max(max, lr.length); } right++; } return max; };
Parses URL Params into an object
let url = 'http://www.domain.com/?user=anonymous&id=123&id=456&city=%E5%8C%97%E4%BA%AC&enabled'; parseParam(url) /* result { user: 'anonymous', id: [ 123, 456 ], // Repeated key s should be assembled into an array, and those that can be converted into numbers should be converted into digital types city: 'Beijing', // Chinese needs to be decoded enabled: true, // unspecified value key convention is true } */
function parseParam(url) { const paramsStr = /.+\?(.+)$/.exec(url)[1]; // Take out the string after the ? const paramsArr = paramsStr.split('&'); // Split the string with & and store it in an array let paramsObj = {}; // store params into object paramsArr.forEach(param => { if (/=/.test(param)) { // handle arguments with value let [key, val] = param.split('='); // Split key and value val = decodeURIComponent(val); // decoding val = /^\d+$/.test(val) ? parseFloat(val) : val; // Determine whether to convert to a number if (paramsObj.hasOwnProperty(key)) { // If the object has a key, add a value paramsObj[key] = [].concat(paramsObj[key], val); } else { // If the object does not have this key, create the key and set the value paramsObj[key] = val; } } else { // handle arguments without a value paramsObj[param] = true; } }) return paramsObj; }
Please implement an add function that satisfies the following functions
add(1); // 1 add(1)(2); // 3 add(1)(2)(3);// 6 add(1)(2, 3); // 6 add(1, 2)(3); // 6 add(1, 2, 3); // 6
function add(...args) { // Declare a function inside, save and collect all parameter values using the characteristics of closure let fn = function(...newArgs) { return add.apply(null, args.concat(newArgs)) } // Using the feature of toString implicit conversion, when the last execution is performed, the implicit conversion is performed, and the final value is calculated and returned fn.toString = function() { return args.reduce((total,curr)=> total + curr) } return fn }
Test site:
- Use closures and have a deep understanding of JavaScript's scope chain (prototype chain)
- Override the toSting() method of the function
// To test, call the toString method to trigger the evaluation add(1).toString(); // 1 add(1)(2).toString(); // 3 add(1)(2)(3).toString();// 6 add(1)(2, 3).toString(); // 6 add(1, 2)(3).toString(); // 6 add(1, 2, 3).toString(); // 6
Implement the chunk method of lodash -- the array is split according to the specified length
topic
/** * @param input * @param size * @returns {Array} */ _.chunk(['a', 'b', 'c', 'd'], 2) // => [['a', 'b'], ['c', 'd']] _.chunk(['a', 'b', 'c', 'd'], 3) // => [['a', 'b', 'c'], ['d']] _.chunk(['a', 'b', 'c', 'd'], 5) // => [['a', 'b', 'c', 'd']] _.chunk(['a', 'b', 'c', 'd'], 0) // => []
accomplish
function chunk(arr, length) { let newArr = []; for (let i = 0; i < arr.length; i += length) { newArr.push(arr.slice(i, i + length)); } return newArr; }
Determine whether it is a phone number
function isPhone(tel) { var regx = /^1[34578]\d{9}$/; return regx.test(tel); }
Implement the getValue/setValue function to get the value corresponding to the path
// example var object = { a: [{ b: { c: 3 } }] }; // path: 'a[0].b.c' var array = [{ a: { b: [1] } }]; // path: '[0].a.b[0]' function getValue(target, valuePath, defaultValue) {} console.log(getValue(object, "a[0].b.c", 0)); // output 3 console.log(getValue(array, "[0].a.b[0]", 12)); // output 1 console.log(getValue(array, "[0].a.b[0].c", 12)); // output 12
accomplish
/** * Tests for a property match */ export function testPropTypes(value, type, dev) { const sEnums = ['number', 'string', 'boolean', 'undefined', 'function']; // NaN const oEnums = ['Null', 'Object', 'Array', 'Date', 'RegExp', 'Error']; const nEnums = [ '[object Number]', '[object String]', '[object Boolean]', '[object Undefined]', '[object Function]', '[object Null]', '[object Object]', '[object Array]', '[object Date]', '[object RegExp]', '[object Error]', ]; const reg = new RegExp('\\[object (.*?)\\]'); // Exact match pattern, type should pass something like format [object Window] [object HTMLDocument] ... if (reg.test(type)) { // Exclude 12 types of nEnums if (~nEnums.indexOf(type)) { if (dev === true) { console.warn(value, 'The parameter type belongs to one of 12 types: number string boolean undefined Null Object Array Date RegExp function Error NaN'); } } if (Object.prototype.toString.call(value) === type) { return true; } return false; } }
const syncVarIterator = { getter: function (obj, key, defaultValue) { // outcome variable const defaultResult = defaultValue === undefined ? undefined : defaultValue; if (testPropTypes(obj, 'Object') === false && testPropTypes(obj, 'Array') === false) { return defaultResult; } // The result variable, which temporarily points to the reference held by obj, may be continuously modified later let result = obj; // get know value try { // Parse attribute hierarchy sequence const keyArr = key.split('.'); // Iterate over obj object properties for (let i = 0; i < keyArr.length; i++) { // If there is a corresponding value for the i-th layer attribute, then iterate over the attribute value if (result[keyArr[i]] !== undefined) { result = result[keyArr[i]]; // Returns undefined if not present } else { return defaultResult; } } } catch (e) { return defaultResult; } // return the fetched result return result; }, setter: function (obj, key, val) { // Returns undefined if obj does not exist if (testPropTypes(obj, 'Object') === false) { return false; } // The result variable, which temporarily points to the reference held by obj, may be continuously modified later let result = obj; try { // Parse attribute hierarchy sequences const keyArr = key.split('.'); let i = 0; // Iterate over obj object properties for (; i < keyArr.length - 1; i++) { // If the value corresponding to the i-th layer attribute does not exist, it is defined as an object if (result[keyArr[i]] === undefined) { result[keyArr[i]] = {}; } // If the value corresponding to the i-th layer attribute is not an instance of Object (Object), an error is thrown if (!(result[keyArr[i]] instanceof Object)) { throw new Error('obj.' + keyArr.splice(0, i + 1).join('.') + 'is not Object'); } // Iterate over the layer property values result = result[keyArr[i]]; } // set attribute value result[keyArr[i]] = val; return true; } catch (e) { return false; } }, };
Use promise s to achieve
Create enhancedObject function
const enhancedObject = (target) => new Proxy(target, { get(target, property) { if (property in target) { return target[property]; } else { return searchFor(property, target); //In actual use, the value should be reset } }, }); let value = null; function searchFor(property, target) { for (const key of Object.keys(target)) { if (typeof target[key] === "object") { searchFor(property, target[key]); } else if (typeof target[property] !== "undefined") { value = target[property]; break; } } return value; }
Use the enhancedObject function
const data = enhancedObject({ user: { name: "test", settings: { theme: "dark", }, }, }); console.log(data.user.settings.theme); // dark console.log(data.theme); // dark
After the above code runs, the console will output the following code:
dark dark
By observing the above output results, we can know that using the object processed by the enhancedObject function, we can easily access the deep properties inside the ordinary object.
implement bind
What to do to implement bind
- Return a function, bind this, and pass preset parameters
- The function returned by bind can be used as a constructor. Therefore, when used as a constructor, this should be invalidated, but the parameters passed in are still valid
// Implementation of mdn if (!Function.prototype.bind) { Function.prototype.bind = function(oThis) { if (typeof this !== 'function') { // closest thing possible to the ECMAScript 5 // internal IsCallable function throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function() {}, fBound = function() { // When this instanceof fBound === true, it means that the returned fBound is called as a new constructor return fToBind.apply(this instanceof fBound ? this : oThis, // Get the parameter passed when calling (fBound). The function parameter returned by bind is often passed in this way aArgs.concat(Array.prototype.slice.call(arguments))); }; // maintain prototype relationship if (this.prototype) { // Function.prototype doesn't have a prototype property fNOP.prototype = this.prototype; } // The following line of code makes fBound.prototype an instance of fNOP, so // If the returned fBound is used as the constructor of new, the new object generated by new is passed to fBound as this, and the __proto__ of the new object is an instance of fNOP fBound.prototype = new fNOP(); return fBound; }; }
Render tens of thousands of data without getting stuck on the page
When rendering large data, use createDocumentFragment and requestAnimationFrame reasonably, and divide the operation into small pieces for execution.
setTimeout(() => { // Insert 100,000 pieces of data const total = 100000; // data inserted once const once = 20; // Number of times required to insert data const loopCount = Math.ceil(total / once); let countOfRender = 0; const ul = document.querySelector('ul'); // How to add data function add() { const fragment = document.createDocumentFragment(); for(let i = 0; i < once; i++) { const li = document.createElement('li'); li.innerText = Math.floor(Math.random() * total); fragment.appendChild(li); } ul.appendChild(fragment); countOfRender += 1; loop(); } function loop() { if(countOfRender < loopCount) { window.requestAnimationFrame(add); } } loop(); }, 0)
Implement a JSON.parse
JSON.parse(text[, reviver])
Used to parse JSON strings and construct JavaScript values or objects described by strings. An optional reviver function is provided to perform transformations (operations) on the resulting object before returning
The first one: call eval directly
function jsonParse(opt) { return eval('(' + opt + ')'); } jsonParse(jsonStringify({x : 5})) // Object { x: 5} jsonParse(jsonStringify([1, "false", false])) // [1, "false", falsr] jsonParse(jsonStringify({b: undefined})) // Object { b: "undefined"}
Avoid using eval unnecessarily. eval() is a dangerous function, and the code it executes has the rights of the executor. If the string code you run with eval() is manipulated and modified by a malicious party (someone with bad intentions), you could end up running malicious code on the user's computer with the permissions of your webpage/extension. It will execute JS code and has XSS vulnerability.
If you only want to remember this method, you have to verify the parameter json.
var rx_one = /^[\],:{}\s]*$/; var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g; var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g; var rx_four = /(?:^|:|,)(?:\s*\[)+/g; if ( rx_one.test( json .replace(rx_two, "@") .replace(rx_three, "]") .replace(rx_four, "") ) ) { var obj = eval("(" +json + ")"); }
The second type: Function
Core: Function has the same string parameter characteristics as eval
var func = new Function(arg1, arg2, ..., functionBody);
In the actual application of converting JSON, only need to do
var jsonStr = '{ "age": 20, "name": "jack" }' var json = (new Function('return ' + jsonStr))();
Both eval and Function can dynamically compile js code, but it is not recommended to use it in actual programming