写好JS | 青训营

85 阅读4分钟

组件设计的原则:封装性,正确性,扩展性,复用性
实现组件的步骤:结构设计 展现效果 行为设计
三次重构:
插件化
模板化
抽象化

使用高阶函数来防止多次触发事件 Once
为了能够让“只执行一次”的需求覆盖不同的事件处理,我们可以将这个需求剥离出来 称为过程抽象

function once(fn){
  return function(...args){
    if(fn){
    	const ret = fn.apply(this , args)
      fn =null
      return ret
    }
  }
}

我们可以理解为函数**参数fn return function(...args)**等价

HOF(高阶函数)
以函数为参数 以函数为返回值 常用于作为函数装饰器

节流防抖

运用场景: 限制函数的执行频次,从而优化函数触发频率过高导致的响应速度跟不上触发频率,导致出现延迟、卡顿的现象以及其他错误

通常用于一些高频率的事件中,比如 鼠标滚动、窗口resize、滚动条滑动 等操作。在这种情况下,我们希望这些事件能够以一定的频率触发(要触发多次),但不是每次事件都触发,节流函数可以规定在一定时间间隔中,该方法只执行一次。这样可以减少函数的执行次数,优化性能。举个简单例子,当用户拖动滚动条时,如果每次滚动都触发事件,页面就会非常频繁的更新UI,造成卡顿。使用节流函数可以限制触发频率,提升页面流畅度。

防抖:处理一些高频触发的事件,比如用户连续点击按钮、输入框频繁输入。 当用户点击按钮过快,导致重复点击,多次调用接口;或者输入框的文字一变化就调用接口,导致多次调用接口。

此时,我们肯定是希望哪怕多次点击按钮,也只调用一次接口;也不希望输入框每输入一个字母就发送一次请求,那样页面就会频繁地发送请求,极大的浪费资源。使用防抖可以在用户输入完毕后再发送请求,或者避免重复点击按钮重复请求,减少函数的执行次数及接口调用,避免频繁更新UI或者发送请求造成性能浪费。 简而言之就是不管触发了多少次回调都只执行最后一次

节流:对于连续触发的事件,每隔一段时间内执行一次,节流里面涉及的时间主要指时间执行的间隔时间。

简而言之就是无论触发多少次回调都只执行第一次

节流函数:

function throttle(fn , time = 500){
 let timer;
  return function(...args){
    if(timer === null){
      	fn.apply(this,args)
        timer = setTimeout(() =>{
        timer = null;
          ),time)
    }
    }
  }
}

//只有当timer === null条件成功才会触发函数
//只有经过time s后才能给timer = null条件
防抖函数:

function debounce(fn , dur){
 dur = dur || 100
  var timer
  return function(){
    clearTimout(timer)
    timer = setTimeout(() => {
      fn.apply(this,args)
    },dur)
  }
}


//只有当dur s之后才会触发定时器内的函数
//每一次调用都会把前一次的定时器给删除
声明式写法实现button三态
image.png

用shift拿到actions的第一个 然后将他push到最后 这样下一次执行就是之前的下一个

交通灯轮询效果
利用wait函数中返回的promise成功后使用的定时器来实现轮询

const traffic = document.getElementById('traffic');

function wait(time){
  return new Promise(resolve => setTimeout(resolve, time));
}

function setState(state){
  traffic.className = state;
}

async function start(){
  //noprotect
  while(1){
    setState('wait');
    await wait(1000);
    setState('stop');
    await wait(3000);
    setState('pass');
    await wait(3000);
  }
}

start();

经典洗牌算法

const cards = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

function shuffle(cards) {
  const c = [...cards];
  for(let i = c.length; i > 0; i--) {
    const pIdx = Math.floor(Math.random() * i);
    [c[pIdx], c[i - 1]] = [c[i - 1], c[pIdx]];
  }
  return c;
}

分红包算法

切西瓜:将随机切一刀 挑被切的多的那一份再切

function generate(amount, count){
  let ret = [amount];
  
  while(count > 1){
    //挑选出最大一块进行切分
    let cake = Math.max(...ret),
        idx = ret.indexOf(cake),
        part = 1 + Math.floor((cake / 2) * Math.random()),
        rest = cake - part;
    
    ret.splice(idx, 1, part, rest);
    
    count--;
  }
  return ret;
}