There are some issues that get discussed a lot in JavaScript, and everyone has different ideas about them, and the best way to understand them is to implement them yourself, without saying a word, and get to the point.
Array flattening
There are many ways to flatten an array, but ultimately the best approach is to recurse and implement a flatten method with a specified depth so that the basics are understood.
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]
Copy the code
The recursive implementation is pretty straightforward, just iterate through each item, and if an item is an array, let that item continue to be called. Depth is specified as the flattening depth, because this parameter is applied to each item in the array, so it is placed in the loop.
Currie,
Everyone has their own way of understanding and implementing it. In a word, the explanation is to execute when there are enough arguments, return a function when there are not enough arguments, and save the previous arguments until there are 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]
Copy the code
If the number of parameters is less than the number of currified parameters, the function is returned; otherwise, the function is executed.
Image stabilization
The way I understand it is that no matter how many times you trigger, you wait until a certain amount of time has passed after you finally trigger. Follow this explanation and 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)
}
}
Copy the code
Now there is a requirement is the beginning of the trigger, the last trigger, and can be configured, write a test page to facilitate the test function, each press the space bar will let the number plus 1, to test the anti-shake and throttling function.
<html lang="zh-cmn-Hans">
<head>
<style>
#container{text-align: center; color: # 333; font-size: 30px; }</style>
</head>
<body>
<div id="container"></div>
<script>
var count = 1
var container = document.getElementById('container')
function getUserAction(e) {
/ / space
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>
Copy the code
Use the leading and trailing parameters to determine whether the start and end are executed. If leading is true, each space press is executed once. If trailing is true, each end is executed for the last time. If the trailing value is false, the getUserAction does not execute after the trailing value is set. If the trailing value is false, the getUserAction does not execute.
function debounce(func, wait, leading, trailing) {
var timer, lastCall = 0, flag = true
return function() {
var context = this
var args = arguments
var now = + new Date(a)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)
}
}
}
Copy the code
If it is smaller than the interval, it will not be executed after the first time. If it is larger than the interval or after the interval, it will reset the flag, which can be compared with the basic version above.
The throttle
Throttling means that no matter how it is triggered, it is performed at specified intervals, also given in the 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)
}
}
}
Copy the code
The same as the anti-shake function with two parameters, can also use the above example to test, in fact, the code is 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
}
}
}
Copy the code
Copy the object
Object copy is known as deep copy and shallow copy, black technology means is to use
JSON.parse(JSON.stringify(obj))
Copy the code
Another way is to use recursion
function clone(value, isDeep) {
if (value === null) return null
if (typeofvalue ! = ='object') 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: { 'a': 1.e: [1, {f: 2}},d: { 'b': 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
Copy the code
For primitive types, return directly, and for reference types, the clone method is iterated recursively.
conclusion
In fact, for the above methods, the general idea is the use of recursion and higher-order functions, including the use of closures, front-end love to ask these questions, it is best to implement their own again, so as to help understand.