This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

preface

I met my elementary school classmates yesterday and didn’t think it mixed so badly – only put a dollar into my bowl O (╥﹏╥) O

Life is so boring, always amuse yourself is not, later I will often tell you jokes, do you want to listen to not O(∩_∩) haha ~

A few days ago wrote a must-have, senior front-end 】 【 30 + high frequency written questions and detailed answers long (word), see the “how” you baffled me handwritten summarizes 30 + common topic implementation, points out many problems, the brothers and sisters have been made without stabilization and throttling, bighead don’t eat not to sleep and have 12 + handwritten topic (close to 42 +), Take a look.

Through train

Click to view the source address of rigong 1 problem (62+ handwritten problem implementation so far)

1. If you

// Stabilization: this can be combined with the scenario where your computer is set to sleep for 10 minutes
// If you are using the computer all the time, the computer will not sleep (frequently turn off the previous timer, turn on the new timer)
Your computer falls asleep 10 minutes after you haven't used it for the last time
const debounce = function (func, delay) {
  let timer = null

  return function (. args) {
    clearTimeout(timer)

    timer = setTimeout(() = > {
      func.apply(this, args)
    }, delay)
  }
}

/ / test
/ / HTML
<input type="text" id="input"/>
/ / js parts
const showName = debounce(function (name) {
  console.log($input.value, this, name)
}, 500)


$input.addEventListener('input'.(e) = > {
  // Stop input within 500ms before output
  showName.call({ name: 'Front End Bighead' }, 'Front End Bighead')})Copy the code

2. The throttle

Throttling: regardless of how you trigger, it will only trigger once in a specified period of time

Timestamp based (Mode 1)

const throttle = function (func, delay) {
  let startTime = Date.now()

  return function (. args) {
    let lastTime = Date.now()

    if (lastTime - startTime > delay) {
      func.apply(this, args)
      startTime = Date.now()
    }
  }
}

/ / test
let t1 = Date.now()

const showName = throttle(function (name) {
  const t2 = Date.now()
  console.log(this, name, t2 - t1)
  t1 = Date.now()
}, 1000)
// The showName function will be executed every 10 milliseconds, but it will be executed every 1 second
setInterval(() = > {
  showName.call({ name: 'Front End Bighead' }, 'Front End Bighead')},10)

// {name: 'bighead'} 'bighead
// {name: 'bighead'} 'bighead' 1001
// {name: 'bighead'} 'bighead' 1006
// {name: 'bighead'} 'bighead' 1006
// {name: 'bighead'} 'bighead' 1005
Copy the code

Based on setTimeout(Method 2)

const throttle2 = function (func, delay) {
  let timer = null

  return function (. args) {
    if(! timer) { timer =setTimeout(() = > {
        func.apply(this, args)
        timer = null
      }, delay) 
    }
  }
}
/ / test
let t1 = Date.now()

const showName = throttle2(function (name) {
  const t2 = Date.now()
  console.log(this, name, t2 - t1)
  t1 = Date.now()
}, 1000)

setInterval(() = > {
  showName.call({ name: 'Front End Bighead' }, 'Front End Bighead')},10)

// {name: 'bighead'} 'bighead
// {name: 'bighead'} 'bighead' 1001
// {name: 'bighead'} 'bighead' 1007
// {name: 'headfish'} 'headfish' 1011
// {name: 'bighead'} 'bighead' 1009
// {name: 'bighead'} 'bighead' 1008
Copy the code

3. Coriolization of functions

const curry = (func, ... args) = > {
  // Get the number of arguments to the function
  const fnLen = func.length

  return function (. innerArgs) {
    innerArgs = args.concat(innerArgs)
    // If the parameters are not collected enough, continue recursive collection
    if (innerArgs.length < fnLen) {
      return curry.call(this, func, ... innerArgs) }else {
      // Otherwise call func with the collected arguments
      func.apply(this, innerArgs)
    }
  }
}
/ / test
const add = curry((num1, num2, num3) = > {
  console.log(num1, num2, num3, num1 + num2 + num3)
})

add(1) (2) (3) // 1 2 3 6
add(1.2) (3) // 1 2 3 6
add(1.2.3) // 1 2 3 6
add(1) (2.3) // 1 2 3 6

Copy the code

4. bind

The bind() method creates a new function, and when bind() is called, this of the new function is specified as the first argument to bind(), and the remaining arguments will be used as arguments to the new function. MDN

The sister call implementation

The sister apply implementation

Function.prototype.bind2 = function (context, ... args) {
  if (typeof this! = ='function') {
    throw new TypeError('Bind must be called on a function')}const executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {
    if(! (callingContextinstanceof boundFunc)) {
      // If the call method is not new func, call sourceFunc directly and give the corresponding argument
      return sourceFunc.apply(context, args)
    } else {
      // Similar to several procedures for executing new
      const self = Object.create(sourceFunc.prototype) // Handle the form of the new call
      const result = sourceFunc.apply(self, args)
      // If the result is not an object function, return self
      if (result && typeof result === 'object' || typeof result === 'function') {
        return result
      } else {
        return self
      }
    }
  }
  const func = this
  
  const bound = function (. innerArgs) {
    return executeBound(func, bound, context, this, args.concat(innerArgs))
  }

  return bound
}

/ / test
// 1. Common call
const showName = function (sex, age) {
  console.log(this, sex, age)
}

showName.bind2({ name: 'Front End Bighead' }, 'boy') (100) // { name: '前端胖头鱼' } 'boy' 100

// 2. new call
const Person = function (name) {
  this.name = name
}

Person.prototype.showName = function (age) {
  console.log(this.this.name, age)
}

const bindPerson = Person.bind(null.'boy')
const p1 = new bindPerson('Front End Bighead')

p1.showName(100) // Person { name: 'boy' } 'boy' 100
Copy the code

5. Implement a simplified template engine

In the era of jQuery, the template engine is still used a lot. It can be understood as a function that takes the template + data through a black box operation and finally gets the page to be displayed

const render = (template, data) = > {
  // \s*? {{name}} {{name}
  return template.replace(/{{\s*? (\w+)\s*? }}/g.(match, key) = > {
    // Replace is read if a match is found, otherwise empty string is replaced
    return key && data.hasOwnProperty(key) ? data[ key ] : ' '})}const data = {
  name: 'Front End Bighead'.age: 100
}
const template = 'I am: {{name}} age is: {{age}}'
console.log(render(template, data))
/* I am: front-end bighead fish age is: 100 */
Copy the code

6. Four ways to convert a class array to an array

// Class arrays are converted to arrays
const arrayLikeObj = {
  0: 'Front End Bighead'.1: 100.length: 2
}

// 1. [].slice
console.log([].slice.call(arrayLikeObj))
// 2. Array.from
console.log(Array.from(arrayLikeObj))
// 3. Array.apply
console.log(Array.apply(null, arrayLikeObj))
// 4. [].concat
console.log([].concat.apply([], arrayLikeObj))


Copy the code

7. Please implement DOM2JSON a function that can output a DOM node in JSON format

Has appeared in byte’s interview

const dom2json = (rootDom) = > {
  if(! rootDom) {return 
  }

  let rootObj = {
    tagName: rootDom.tagName,
    children: []}const children = rootDom.children
  // Read the child node (element node)
  if (children && children.length) {
    Array.from(children).forEach((ele, i) = > {
      // recursive processing
      rootObj.children[ i ] = dom2json(ele)
    })
  }

  return rootObj
}


Copy the code

test

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <title>dom2json</title>
</head>
<body>
  <div class="box">
    <p class="p">hello world</p>
    <div class="person">
      <span class="name">Front end bighead fish</span>
      <span class="age">100</span>
    </div>
  </div>
  <script>
    const dom2json = (rootDom) = > {
      if(! rootDom) {return 
      }

      let rootObj = {
        tagName: rootDom.tagName,
        children: []}const children = rootDom.children

      if (children && children.length) {
        Array.from(children).forEach((ele, i) = > {
          rootObj.children[ i ] = dom2json(ele)
        })
      }

      return rootObj
    }

    const json = dom2json(document.querySelector('.box'))

    console.log(json)
  </script>
</body>
</html>

Copy the code

8. List to tree structure

I believe you have encountered similar problems in your work. The front end needs data in a tree structure, but the back end returns a list. We need to convert the list into a tree structure (of course, here you can also tell your back end classmates why they don’t give me the data I want).

const arrayToTree = (array) = > {
  const hashMap = {}
  let result = []

  array.forEach((it) = > {
    const { id, pid } = it

    // If the tree does not exist, declare the children tree first
    // This step may also appear below
    if(! hashMap[id]) { hashMap[id] = {children: [] } } hashMap[id] = { ... it,children: hashMap[id].children
    }
    // Process the current item
    const treeIt = hashMap[id]

    // Root node, push directly
    if (pid === 0) {
      result.push(treeIt)
    } else {
      // It is also possible that the parent node of the current node has not yet joined the hashMap and needs to be handled separately
      if(! hashMap[pid]) { hashMap[pid] = {children: []}}// If it is not the root node, find the parent node and insert yourself into the children of the parent node
      hashMap[pid].children.push(treeIt)
    }
  })

  return result
}

/ / test
const data = [
  // Note that the element with pid 1 is placed first
  { id: 2.name: '2'.pid: 1 },
  { id: 1.name: '1'.pid: 0 },
  { id: 3.name: '3'.pid: 1 },
  { id: 4.name: '4'.pid: 3 },
  { id: 5.name: '5'.pid: 4 },
  { id: 7.name: '7'.pid: 6},]console.log(JSON.stringify(arrayToTree(data), null.2))
/ * [{" id ": 1," name ":" unit 1 ", "pid" : 0, "children" : [{" id ": 2," name ":" department 2 ", "pid" : 1, "children" : []}, {" id ": Department of 3, "name" : "3", "pid" : 1, "children" : [{" id ": 4," name ":" unit 4 ", "pid" : 3, "children" : [{" id ": 5," name ": Department of "5", "pid" : 4, "children" :}}}} []]]]] * /
Copy the code

9. Tree structure transfer list

You can try it the other way around

const tree2list = (tree) = > {
  let list = []
  let queue = [...tree]

  while (queue.length) {
    // Start fetching nodes from the front
    const node = queue.shift()
    const children = node.children
    // Take the children of the current node and queue them for the next loop
    if(children.length) { queue.push(... children) }// Delete the extra children tree
    delete node.children
    // Add to the list
    list.push(node)
  }

  return list
}

/ / test
const data = [
  {
    "id": 1."name": Department of "1"."pid": 0."children": [{"id": 2."name": "Department of 2"."pid": 1."children": []}, {"id": 3."name": "Unit 3"."pid": 1."children": [{"id": 4."name": "Department of 4"."pid": 3."children": [{"id": 5."name": Department of "5"."pid": 4."children": []}]}]}]console.log(tree2list(data))
/ * [{id: 1, name: '1', pid: 0}, {id: 2, name: '2', pid: 1}, {id: 3, name: '3', pid: 1}, {id: 4, name: '4', pid, 3}, {5, id: name: '5', pid: 4}] * /

Copy the code

10. sleep

Implement a function, n seconds after the function func

const sleep = (func, delay) = > {
  return new Promise((resolve) = > {
    setTimeout(() = > {
      resolve(func())
    }, delay)
  })
}

const consoleStr = (str) = > {
  return () = > {
    console.log(str)
    return str
  }
}

const doFns = async() = > {const name = await sleep(consoleStr('Front End Bighead'), 1000)
  const sex = await sleep(consoleStr('boy'), 1000)
  const age = await sleep(consoleStr(100), 1000)

  console.log(name, sex, age)
}

doFns()
// Front-end bighead fish 1s later
// boy 2s later
// 100 3s later
// Front end Bighead boy 100

Copy the code

Fibonacci series

Fibonacci numbers, usually denoted by F(n), form a sequence called the Fibonacci sequence. The series consists of01At the beginning, each of the following numbers is the sum of the preceding two. So that's F of0) = 0, F (1) = 1
F(n) = F(n - 1) + F(n - 2), where n >1I give you n, please calculate F(n). The sample1Input:2Output:1Explanation: F (2) = F(1) + F(0) = 1 + 0 = 1The sample2Input:3Output:2Explanation: F (3) = F(2) + F(1) = 1 + 1 = 2The sample3Input:4Output:3Explanation: F (4) = F(3) + F(2) = 2 + 1 = 3


Copy the code

Violence to achieve

According to the problem, it is easy to write the following recursive violence code

const fib = (n) = > {
  if (n === 0) {
    return 0
  }

  if (n === 1 || n === 2) {
    return 1
  }

  return fib(n -2) + fib(n - 1)}/ / test
console.log(fib(1)) / / 1
console.log(fib(2)) / / 1
// Try counting the computation time
const t1 = Date.now()
console.log(fib(44)) / / 701408733
console.log(Date.now() - t1) / / close to 4393
Copy the code

Cache optimization

The code above does the trick, but the performance is not good. Let’s look at a procedure to calculate fib(10)

10 / / calculation
10= >9 + 8 // We need to calculate 9 and 8
9= >8 + 7 // We need to calculate 8 and 7
8= >7 + 6 // Need to calculate 7 and 6
7= >6 + 5 // We need to calculate 6 and 5
6= >5 + 4 // We need to calculate 5 and 4
5= >4 + 3 // We need to calculate 4 and 3
4= >3 + 2 // We need to calculate 3 and 2
2= >1 + 0 // Need to calculate 1 and 0
Copy the code

In this process, the code that follows the above violence will repeat several times some of the previously calculated values, such as 8, 7, 6, 5… Wait, this loss is not necessary, so we can cache the results of the calculation, and the next time we find the same value, just return it

const fib = (n) = > {
  // Cache returns directly
  if (typeoffib[ n ] ! = ='undefined') {
    return fib[ n ]
  }

  if (n === 0) {
    return 0
  }

  if (n === 1 || n === 2) {
    return 1
  }

  const res = fib(n -2) + fib(n - 1)
  // Cache the result of the calculation
  fib[ n ] = res

  return res
}

console.log(fib(1)) / / 1
console.log(fib(2)) / / 1

const t1 = Date.now()
console.log(fib(44)) / / 701408733
console.log(Date.now() - t1) // 1ms

Copy the code

12. Implement the sum function

Implement a function sum that satisfies this rule

sum(1.2.3).valueOf() / / 6
sum(2.3) (2).valueOf() / / 7
sum(1) (2) (3) (4).valueOf() / / 10
sum(2) (4.1) (2).valueOf() / / 9

Copy the code

Analysis of the

A close look at these calls yields the following information

  1. The sum function can take one or more arguments

  2. The sum function returns a new function and can pass one or more arguments

  3. The final calculation is done when.valueof is called

Does this look like a function corrification? The previous function call simply caches the arguments of each call, whereas the valueOf call takes the arguments and sums them up once and returns the result

const sum = (. args) = > {
  // Add is used to cache parameters
  // Note that after the add call is complete, the add function itself is returned so that it can be called chained
  const add = (. args2) = > {
    args = [ ...args, ...args2 ]
    return add
  }
  // Sum calculation
  add.valueOf = () = > args.reduce((ret, num) = > ret + num, 0)

  return add
}

/ / test
console.log(sum(1.2.3).valueOf()) / / 6
console.log(sum(2.3) (2).valueOf()) / / 7
console.log(sum(1) (2) (3) (4).valueOf()) / / 10
console.log(sum(2) (4.1) (2).valueOf()) / / 9

Copy the code

At the end

“Welcome to the discussion in the comments section. The excavation authorities will draw 100 nuggets in the comments section after project Diggnation. See the event article for details.”