JS高阶编程技巧-----curring函数

160 阅读3分钟

1.函数柯理化

函数柯理化:预先处理的思想「形成一个不被释放的闭包,把一些信息存储起来,以后基于作用域链,访问到事先存储的信息,然后进行相关的处理,所有符合这种模式(或者闭包应用的)都被称为柯理化函数」

案例:实现求和

function curring(x) {
  return function (...args) {
    args.unshift(x);
    return args.reduce((result, item) => result + item);
  };
}
var sum = curring(10);
console.log(sum(20)); //10+20
console.log(sum(20, 30)); //10+20+30

2.关于 curring 函数的应用

实现:

let res = add(1)(2)(3);
console.log(res); //->6

res = add(1, 2, 3)(4);
console.log(res); //->10

res = add(1)(2)(3)(4)(5);
console.log(res); //->15

/*
 步骤:
 1.编写一个add函数,其参数用剩余运算符传入,其返回值仍然是一个函数
 2.在返回的函数中可能还要调用当前函数。
 3.进行参数处理:
 4.知识点:基于函数进行运算,或者输出的时候,一般都会调用函数的toString。所以我们会在toString做我们的求和操作
 */
let add = function add(...args) {
  const proxy = function proxy(...arg) {
    args = args.concat(arg);
    return proxy;
  };
  proxy.toString = function () {
    return args.reduce((prev, item) => {
      return prev + item;
    }, 0);
  };
  return proxy;
};
let res = add(1)(2)(3);
console.log(res); //->6

res = add(1, 2, 3)(4);
console.log(res); //->10

res = add(1)(2)(3)(4)(5);
console.log(res); //->15
--------方案二---------
const curring = function curring() {
  let params = [];
  const add = function add(...arg) {
    params = params.concat(arg);
    return add;
  };
  add.toString = function () {
    return params.reduce((prev, item) => {
      return prev + item;
    }, 0);
  };
  return add;
};
let add = curring();
let res = add(1)(2)(3);
console.log(res); //->6

add = curring();
res = add(1, 2, 3)(4);
console.log(res); //->10

add = curring();
res = add(1)(2)(3)(4)(5);
console.log(res); //->15

防抖和节流:

  • 函数的防抖(debounce)和节流(throttle)

    在“高频”触发的场景下,需要进行防抖和节流

    • 狂点一个按钮

    • 页面滚动

    • 输入模糊匹配

    • ...

  • 我们自己设定,多长的时间内,触发两次及以上就算“高频”:封装方法的时候需要指定这个频率(可以设置默认值)

    -「防抖」在某一次高频触发下,我们只识别一次(可以控制开始触发,还是最后一次触发);详细:假设我们规定 500MS 触发多次算是高频,只要我们检测到是高频触发了,则在本次频繁操作下(哪怕你操作了 10min)也是只触发一次...

    -「节流」在某一次高频触发下,我们不是只识别一次,按照我们设定的间隔时间(自己规定的频率),没到达这个频率都会触发一次;详细:假设我们规定频率是 500MS,我们操作了 10min,触发的次数=(10601000)/500

防抖案例

let button = document.querySelector(".button");
const debouce = function (func, wait, immdiate) {
  //对参数进行处理
  if (typeof func !== "function") return;
  if (typeof wait !== "number") {
    if (typeof wait === "boolean") {
      immdiate = wait;
    }
  }
  if (typeof wait === "undefined") {
    wait = 500;
  }
  if (typeof immdiate === "undefined") {
    immdiate = false;
  }
  let timer = null;

  return function (...arg) {
    let self = this;
    let now = immdiate && !timer ? true : false;
    console.log(now);
    //清除定时器
    clearTimeout(timer);
    timer = setTimeout(function () {
      timer = null;
      //执行func的时候确保this是Dom元素,并且闯进去的参数有事件对象
      !immdiate ? func.call(self, ...arg) : null;
    }, wait);
    now ? func.call(self, ...arg) : null;
  };
};

button.onclick = debouce(
  function () {
    console.log("ok");
  },
  5000,
  true
); //true代表点击之后立即执行,false代表疯狂点击的最后一次执行

节流案例:

const throttle = function throttle(func, interval) {
  //对参数初始化
  if (typeof func !== "function") return;
  if (typeof interval === "undefined") {
    interval = 500;
  }
  let pre = 0, //上次触发的时间
    timer = null;
  return function (...args) {
    let now = new Date(),
      self = this;
    let remaining = interval - (now - pre);
    //两次触发的时间间隔大于500ms==》立即执行
    if (remaining <= 0) {
      clearTimeout(timer);
      timer = null; //让下次如果没有超过500能实行定时器
      pre = now;
      func.call(this, ...args);
    } else if (!timer) {
      //两次触发时间间隔小于500ms==》
      timer = setTimeout(() => {
        clearTimeout(timer); //如果间隔小于500ms的等待时间恰好有触发了一次,清除定时器
        timer = null;
        pre = new Date();
        func.call(this, ...args);
      }, remaining);
    }
  };
};
window.onscroll = throttle(function () {
  console.log("ok");
}, 5000);