视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
JS数组扁平化防抖与节流对象拷贝
2020-11-27 19:37:15 责编:小采
文档


这次给大家带来JS数组扁平化防抖与节流对象拷贝,JS数组扁平化防抖与节流对象拷贝的注意事项有哪些,下面就是实战案例,一起来看一下。

数组扁平化

数组扁平化有很多方法,但最终最好的方法就是递归,实现一个指定深度的扁平化方法,这样基本的套路都会了解。

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 ]

递归实现很简洁易懂,就是将每一项遍历,如果某一项为数组,则让该项继续调用,这里指定了 depth 作为扁平化的深度,因为这个参数对数组的每一项都要起作用,故放在循环的里面。

柯里化

函数的柯里化都被讲烂了,每个人都有自己的理解和实现方法,一句话解释就是参数够了就执行,参数不够就返回一个函数,之前的参数存起来,直到够了为止。

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]

上面的代码不难看出,每次判断参数的个数,与被柯里化的函数参数个数比较,如果小于就继续返回函数,否则就执行。

防抖

防抖按照我的理解就是不管你触发多少次,都等到你最后触发后过一段你指定的时间才触发。按照这个解释,写一个基本版的。

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

现在有个要求就是刚开始的时候也触发,最后一次也触发,并且可以配置,先写个测试页面方便测试功能,每次按空格键就会让数字加1,来测试防抖和节流函数。

<!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('container')
 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>

通过 leading 和 trailing 两个参数来决定开始和结束是否执行,如果 leading 为 true,则没次按空格都会执行一次,如果 trailing 为 true,则每次结束都会将最后一次触发执行。以防抖函数距离,如果两者都为 true,则第一次按空格会加 1,然后快速按空格,此时里面的 getUserAction 并不会执行,而是等到松手后再执行,加入 trailing 为 false,则松手后不会执行。

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)
 }
 }
}

解释一下,每次记录上次调用的时间,与现在的时间对比,小于间隔的话,第一次执行后之后就不会执行,大于间隔或在间隔时间后调用了,则重置 flag,可以与上面那个基本版的对比着看。

节流

节流就是,不管怎么触发,都是按照指定的间隔来执行,同样给个基本版。

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)
 }
 }
}

同样和防抖函数一样加上两个参数,也可使用上面的例子来测试,其实两者的代码很类似。

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
 }
 }
}

对象拷贝

对象拷贝都知道分为深拷贝和浅拷贝,黑科技手段就是使用

JSON.parse(JSON.stringify(obj))

还有个方法就是使用递归了

function clone(value, isDeep) {
 if (value === null) return null
 if (typeof value !== '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

相信看了本文案例你已经掌握了方法,更多精彩请关注Gxl网其它相关文章!

推荐阅读:

项目中如何使用better-scroll插件

jQuery+Cookie切换风格

下载本文
显示全文
专题