Home >Web Front-end >JS Tutorial >Detailed explanation of five common functions in JavaScript

Detailed explanation of five common functions in JavaScript

小云云
小云云Original
2018-03-26 09:07:521328browse

There are some issues in JavaScript that are often discussed. Everyone has different ideas about these issues. The best way to understand these issues is to implement them yourself. Without further ado, let’s get down to the topic.

Array flattening

There are many ways to flatten arrays, but in the end the best way is to recurse and implement a flattening method with a specified depth, so that you can understand the basic routines.


function flattenDepth(array, depth = 1) {
 let result = []
 array.forEach(item => {
 let d = depth
 if (Array.isArray(item) && d > 0) {
  result.push(...(flattenDepth(item, --d)))
 } else {
  result.push(item)
 }
 })
 return result
}
console.log(flattenDepth([1, [2, [3, [4]], 5]])) // [ 1, 2, [ 3, [ 4 ] ], 5 ]
console.log(flattenDepth([1, [2, [3, [4]], 5]], 2)) // [ 1, 2, 3, [ 4 ], 5 ]
console.log(flattenDepth([1, [2, [3, [4]], 5]], 3)) // [ 1, 2, 3, 4, 5 ]

The recursive implementation is very simple and easy to understand, that is, traversing each item. If an item is an array, let the item continue to be called. The depth is specified here as the flat Depth of optimization, because this parameter affects every item in the array, it is placed inside the loop.

Currying

Currying of functions has been talked about badly. Everyone has their own understanding and implementation method. One sentence explanation is that if there are enough parameters, it will be executed, if there are not enough parameters, it will be executed. Returns a function with the previous parameters stored until enough.


function curry(func) {
 var l = func.length
 return function curried() {
 var args = [].slice.call(arguments)
 if(args.length < l) {
  return function() {
  var argsInner = [].slice.call(arguments)
  return curried.apply(this, args.concat(argsInner))
  }
 } else {
  return func.apply(this, args)
 }
 }
}
var f = function(a, b, c) {
 return console.log([a, b, c])
};
var curried = curry(f)
curried(1)(2)(3) // => [1, 2, 3]
curried(1, 2)(3) // => [1, 2, 3]
curried(1, 2, 3) // => [1, 2, 3]

It is not difficult to see from the above code that each time the number of parameters is judged, it is compared with the number of curried function parameters. If it is less than the number, it continues to return the function. Otherwise execute.

Anti-shake

According to my understanding, anti-shake means that no matter how many times you trigger it, it will not trigger until a period of time you specify after the last trigger. Following this explanation, write a basic version.


function debounce(func, wait) {
 var timer
 return function() {
 var context = this
 var args = arguments
 clearTimeout(timer)
 timer = setTimeout(function() {
  func.apply(context, args)
 }, wait)
 }
}

Now there is a requirement that it will be triggered at the beginning and the last time, and it can be configured. First, write a test page to facilitate testing the function. Press space every time Pressing the key will increase the number by 1 to test the anti-shake and throttling functions.


<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
 <style>
  #container{text-align: center; color: #333; font-size: 30px;}
 </style>
</head>
<body>
 <p id="container"></p>
 <script>
  var count = 1
  var container = document.getElementById(&#39;container&#39;)
  function getUserAction(e) {
  // 空格
  if (e.keyCode === 32) {
   container.innerHTML = count++
  }
  }
  // document.onkeydown = debounce(getUserAction, 1000, false, true)
  document.onkeydown = throttle(getUserAction, 1000, true, true)
  function debounce(func, wait, leading, trailing) {}
  function throttle(func, wait, leading, trailing) {}
 </script>
</body>
</html>

The two parameters leading and trailing are used to determine whether the start and end are executed. If leading is true, it will be executed every time the space is pressed. If trailing is true, Then each time it ends, the last trigger will be executed. Anti-shake function distance, if both are true, pressing space for the first time will add 1, and then pressing space quickly, the getUserAction inside will not be executed at this time, but will be executed after letting go. Add trailing to false , it will not be executed after letting go.


function debounce(func, wait, leading, trailing) {
 var timer, lastCall = 0, flag = true
 return function() {
 var context = this
 var args = arguments
 var now = + new Date()
 if (now - lastCall < wait) {
  flag = false
  lastCall = now
 } else {
  flag = true
 }
 if (leading && flag) {
  lastCall = now
  return func.apply(context, args)
 }
 if (trailing) {
  clearTimeout(timer)
  timer = setTimeout(function() {
  flag = true
  func.apply(context, args)
  }, wait)
 }
 }
}

Explain that each time the time of the last call is recorded, compare it with the current time. If it is less than the interval, it will not be executed after the first execution. If it is greater than If it is called after the interval or after the interval, the flag will be reset. You can compare it with the basic version above.

Throttling

Throttling means that no matter how it is triggered, it will be executed according to the specified interval. There is also a basic version.


function throttle(func, wait) {
 var timer
 return function() {
 var context = this
 var args = arguments
 if (!timer) {
  timer = setTimeout(function () {
  timer = null
  func.apply(context, args)
  }, wait)
 }
 }
}

It also adds two parameters like the anti-shake function. You can also use the above example to test. In fact, the codes of the two are very similar.


function throttle(func, wait, leading, trailing) {
 var timer, lastCall = 0, flag = true
 return function() {
 var context = this
 var args = arguments
 var now = + new Date()
 flag = now - lastCall > wait
 if (leading && flag) {
  lastCall = now
  return func.apply(context, args)
 }
 if (!timer && trailing && !(flag && leading)) {
  timer = setTimeout(function () {
  timer = null
  lastCall = + new Date()
  func.apply(context, args)
  }, wait)
 } else {
  lastCall = now
 }
 }
}

Object copy

We all know that object copy is divided into deep copy and shallow copy. The black technology method is to use

JSON.parse(JSON.stringify(obj))

Another method is to use recursion


##

function clone(value, isDeep) {
 if (value === null) return null
 if (typeof value !== &#39;object&#39;) return value
 if (Array.isArray(value)) {
 if (isDeep) {
  return value.map(item => clone(item, true))
 }
 return [].concat(value)
 } else {
 if (isDeep) {
  var obj = {}
  Object.keys(value).forEach(item => {
  obj[item] = clone(value[item], true)
  })
  return obj
 }
 return { ...value }
 }
}
var objects = { c: { &#39;a&#39;: 1, e: [1, {f: 2}] }, d: { &#39;b&#39;: 2 } }
var shallow = clone(objects, true)
console.log(shallow.c.e[1]) // { f: 2 }
console.log(shallow.c === objects.c) // false
console.log(shallow.d === objects.d) // false
console.log(shallow === objects) // false

For basic types, return directly, For reference types, the clone method is called recursively.

Summary

In fact, for the above methods, the general idea is the use of recursion and higher-order functions, including the use of closures. The front-end likes to ask these questions. It is best to Just implement it yourself, which will help your understanding.


Related recommendations:

Various common function definition methods in JavaScript_javascript skills

Summary of js function related knowledge points Share

Explanation of passing by value of js function parameters

The above is the detailed content of Detailed explanation of five common functions in JavaScript. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn