数组扁平化,柯里化,防抖,节流,对象拷贝

数组扁平化:使用递归实现

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([[0,1],[2,3],[4,5]],2))
        console.log(flattenDepth([1,[2,[3,[4]],5]]))
        console.log(flattenDepth([1,[2,[3,[4]],5]],2))
        console.log(flattenDepth([1,[2,[3,[4]],5]],3))

将每一项遍历,如果某一项为数组,则让该项继续调用,这里指定了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)

节流和防抖

函数节流和函数防抖都是对大量频繁调用代码的一种优化。

防抖

不管你触发了多少次,都等到你最后触发后过一段你指定的时间才触发。简单地说,即函数在特定的时间内不被再调用后执行。

实际应用场景

监听窗口大小重绘的操作。
在用户拖拽窗口时,一直在改变窗口的大小,如果我们在 resize 事件中进行一些操作,消耗将是巨大的。而且大多数可能是无意义的执行,因为用户还处于拖拽的过程中。
可以使用 函数防抖 来优化相关的处理。

// 普通方案
window.addEventListener('resize', () => {
  console.log('trigger');
})

//函数防抖方案
let debounceIdentify = 0;
window.addEventListener('resize', () => {
  debounceIdentify && clearTimeout(debounceIdentity)
  debounceIdentity = setTimeout(() => {
    console.log('trigger')
  }, 300)
})

我们在 resize 事件中添加了一个 300 ms 的延迟执行逻辑。
并且每次事件触发时,都会重新计时,这样保证,函数的执行肯定是在距离上次 resize 事件被触发的 300 ms 后。
两次 resize 事件间隔小于 300 ms 的都被忽略了,这样就会节省很多无意义的事件触发。

输入框的联想

几乎所有的搜索引擎都会对你输入的文字进行预判,并在下方推荐相关的结果。
但是这个联想意味着我们需要将当前用户所输入的文本传递到后端,并获取返回数据,展示在页面中。
如果遇到打字速度快的人,在一小段时间内,会连续发送大量的 ajax 请求到后端。并且当前的数据返回过来后,其实已经失去了展示的意义,因为用户可能从 you 输入到了 young ,这两个单词的相关结果肯定不一样的。
所以我们就在监听用户输入的事件那里做函数防抖处理,在 XXX 秒后发送联想搜索的 ajax 请求。

/**
 * 函数防抖的实现
 * @param  {Function} func   要实现函数节流的原函数
 * @param  {Number}   delay  结束的延迟时间
 * @return {Function}        添加节流功能的函数
 */

function debounce (func, delay) {
  let debounceIdentify = 0
  return (...args) => {
    debounceIdentify && clearTimeout(debounceIdentify)
    debounceIdentify = setTimeout(() => {
      debounceIdentify = 0
      func.apply(this, args)
    }, delay)
  }
}

基本版的:

function debounce(func, wait){
   var timer;
   return function(){
     var context = this;
     var args = arguments;
     clearTimeout(timer);
     timer = setTimeout(function(){
       func.apply(context, args)
     }, wait)
   }
}
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)
    }
  }
}

类似函数防抖操作

在一些与用户的交互上,比如提交表单后,一般都会显示一个loading框来提示用户,他提交的表单正在处理中。
但是发送表单请求后就显示loading是一件很不友好的事情,因为请求可能在几十毫秒内就会得到响应。
这样在用户看来就是页面中闪过一团黑色,所以可以在提交表单后添加一个延迟函数,在XXX秒后再显示loading框。
这样在快速响应的场景下,用户是不会看到一闪而过的loading框,当然,一定要记得在接收到数据后去clearTimeout.

let identify = setTimeout(showLoadingModal, 500)
fetch('XXX').then(res => {
  // doing something

  // clear timer
  clearTimeout(identify)
})

节流

不管怎么触发,都是按照指定的时间间隔来执行。简单地说,就是限制函数在一定时间内调用的次数。

在程序中,可以通过限制函数的调用频率,来抑制资源的消耗。

    1. 需要实现一个元素拖拽的效果,可以在每次 move 事件中进行重绘 DOM,但是这样做,程序的开销是非常大的。
      所以这里用到函数节流的方法,来减少重绘的次数。
//普通方案
$dragable.addEventListener('mousemove', () => {
  console.log('trigger')
})

// 函数节流的实现方案
let throttleIndentify = 0;
$dragable.addEventListener('mousemove', () => {
  if(throttleIndentify) return;
  throttleIndentify = setTimeout(() => throttleIdentify = 0, 500);
  console.log('trigger');
})

这样做的效果是,在拖拽的过程中,能保证 500 ms 内,只能重绘一次 DOM。 在同时监听了 mousemove 后,两者最终的效果是一致的,但是在拖拽的过程中,函数节流 版触发事件的次数会减少很多,资源相应地会消耗更少。

  1. 通用的函数节流实现
// ES6 版
function throttle (func, interval) {
  let identify = 0;
  return (...args) => {
    if (identify) return;
    identify = setTimeout(() => identify = 0, interval);
    func.apply(this, args)
  }
}
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
    }
  }
}

类似函数节流的操作

平时开发中经常会做的 ajax 请求获取数据,这里可以用到类似函数节流的操作。
在我们发送一个请求到后台时,当返回的数据还没有接收到,我们会添加一个标识,来表明当前有一个请求正在被处理,如果这时用户再触发 ajax 请求,则会直接跳过本次函数的执行。
同样的还有滑动加载更多数据,如果不添加类似的限制,可能会导致发送更多条请求,渲染重复数据。

对象拷贝

对象拷贝分为深拷贝和浅拷贝

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
原文地址:https://www.cnblogs.com/love314159/p/8822326.html