写好JS的原则之过程抽象

过程抽象

过程抽象

  • 用来处理局部细节控制
  • 过程抽象是函数思想的基础
    image.png
    在想象过程抽象中,可以抽象成有一个房间,房间里面的门,窗,然后房间空间本身都是数据,但是开门或者开窗这个动作、行为就是过程,也就说我们不仅可以将门,窗,空间抽象成数据,这个过程也是可以来作为抽象对象的。

image.png

操作次数限制

操作次数限制常用场景有

  • 一些异步交互
  • 一次性的HTTP请求

通过高阶函数,以函数作为参数,就能得到写出一个只执行一次或者限制次数的函数,例如下面Once()函数,这个函数的参数是一个函数fn,然后执行时会返回一个函数出去,在返回函数中间进行判断fn是否存在,如果存在则用实际参数执行fn,然后将fn=null这样下次就不会执行该函数。例如下面,我声明了一个show函数,其中求a+b的和,并且打印了字符串,在下面我讲这个函数赋值给foo=once(show),然后调用了三次foo(),控制台中只执行了一次。

function once(fn){ 
    return function(...args){
        if(fn){ //判断函数是否存在,如果存在则用实际参数调用它,然后把它置为空
            const ret = fn.apply(this, args);// 用实际参数执行函数
            fn = null;// 置空,下次就不会执行判断语句里面的内容就不会调用函数
            return ret;// 把fn的结果返回出去
        }
    }
}
function show(a, b) {
    let ans = a + b
    console.log("打一下~");
    return ans
}
let foo = once(show);
console.log(foo(10, 20));//"打一下~ 30

console.log(foo(30, 40));//undeifined
console.log(foo(50, 60));//undeifined

image.png

Once

  • 为了能够让“只执行一次”的需求覆盖不同的事件处理,我们将这个需求剥离处理。这个过程我们成为 过程抽离

高阶函数

高阶函数

  • 以函数做为参数
  • 以函数作为返回值
  • 常用于作为函数装饰器

image.png
HOH0函数

function HOH0(fn) {
    return function (...args) {
            return fn.apply(this, args);
        }
    }
}

HOH0函数也叫0级高阶函数,也是等价装饰器,不管你传是什么样的fn都会以原始的参数去执行fn,调用HFH0(fn)去执行等价于直接执行fn,在高阶函数中也叫等价范式,once()和其他函数都是基于该等价范式去扩展

其他常用高阶函数

Once

在上面~

节流函数(Throttle)

点击这里查看实例

节流函数的作用: 假设后台需要记录一个用户的行为,例如鼠标移动,但是用户会经常移动鼠标,即使用户稍微移动下,也会发送很多数据到后台去,这个就会造成很大的带宽浪费,用户移动的鼠标的数据不是说要完全的发送给后台去,我们可以设定一个间隔时间来记录一次数据就可以限制其数据。

节流函数的思路: 使用高级函数思路,以原始函数fn为参数,返回一个函数作为结果,我们会设置一个timer,如果这个timer没有的话就执行fn,同时会给这个timer注册一个setTimeout,在指定的时间后把timer=null,timer存在的时间内,无论怎么调用这个节流函数,因为timer不为空,所以都不会执行fn

function throttle(fn, time = 500){
  let timer;
  return function(...args){
    if(timer == null){ // 如果timer不为空则不进入判断体,就不会再次执行fn
      fn.apply(this,  args);
      timer = setTimeout(() => {
        timer = null;
      }, time)
    }
  }
}
防抖函数(Debounce)

点击这里查看实例

防抖函数的作用: 当记录鼠标移动的时候,如果我们一直胡乱移动鼠标,是不会记录鼠标,只有当鼠标停止的时候才会记录,例如下面的小鸟,当我们胡乱移动鼠标的时候,它并不会移动,只有当鼠标停止它才会移动过来

2.gif

节流函数的思路: 仍然使用高级函数思路,依然用一个timer来记录,每次移动的时候清除掉上一个timer定时器,然后又给这个timer重新注册一个setTimeout定时器,只有当定时器自动执行结束后才会执行fn

function debounce(fn, dur){
  dur = dur || 100;
  var timer;
  return function(){
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, arguments);
    }, dur);//只有当定时器自动结束的时候才会调用里面的函数
  }
}
Consumer/2

点击这里查看实例

function consumer(fn, time){
  let tasks = [],
      timer;
  
  return function(...args){
    tasks.push(fn.bind(this, ...args));
    if(timer == null){
      timer = setInterval(() => {
        tasks.shift().call(this)
        if(tasks.length <= 0){
          clearInterval(timer);
          timer = null;
        }
      }, time)
    }
  }
}
批量操作元素(Iterative)

点击这里查看实例

该函数作用:可以去批量的操作元素,比如修改多个元素的样式,比如设置多个元素的color

先判断这个对象是否可以迭代,如果可迭代便取其每一个元素,然后调用fn方法,然后将结果推送到ret数组然后返回出来

const isIterable = obj => obj != null 
  && typeof obj[Symbol.iterator] === 'function';//申明一个函数判断obj是否是可迭代对象
  
function iterative(fn) {
  return function(subject, ...rest) {
    if(isIterable(subject)) {
      const ret = [];
      for(let obj of subject) {
        ret.push(fn.apply(this, [obj, ...rest]));
      }
      return ret;
    }
    return fn.apply(this, [subject, ...rest]);
  }
}

编程范式

  • 编程范式: 包括JavaScript等很多现代脚本语言是混合的编程范式,编程范式是有几种分类的,大的分类分成命令式声明式
  • 命令式 又分成过程式面向对象;
  • 声明式 又分成逻辑式函数式;
  • JavaScript这种现代脚本语言是一种混合的编程范式,多少都既带有这种命令式,也带有声明式的特点,所以我们可以通过JS写出符合命令式 风格的代码, 也可以写出声明式风格的代码,命令式声明式 没有优劣之分。同时支持两种风格语言让JavaScript的写法更加灵活

image.png

命令式风格的代码

let list = [1, 2, 3, 4];
let map = [];
for (let i = 0; i < list.length; i++) {
    map.push(list[i] * 2);
}

声明式风格的代码

let list = [1, 2, 3, 4];
const double = x => x * 2;
list.map(double);

例子

命令式声明式 在不同的场景会有不同的表现
image.png

Toggle–命令式

点击这里查看实例

switcher.onclick = function(evt){
  if(evt.target.className === 'on'){
    evt.target.className = 'off';
  }else{
    evt.target.className = 'on';
  }
}
Toggle–声明式

点击这里查看实例

function toggle(...actions){
  return function(...args){
    let action = actions.shift();
    actions.push(action);
    return action.apply(this, args);
  }
}

switcher.onclick = toggle(
  evt => evt.target.className = 'off',
  evt => evt.target.className = 'on'
);
Toggle–三态

点击这里查看实例

如果是添加三个状态或者多个状态,在命令式添加其他状态则需要添加if---else分支, 在声明式下面则是添加一个状态即可,在这个例子中选择声明式更加合适

function toggle(...actions){
  return function(...args){
    let action = actions.shift();
    actions.push(action);
    return action.apply(this, args);
  }
}

switcher.onclick = toggle(
  evt => evt.target.className = 'warn',
  evt => evt.target.className = 'off',
  evt => evt.target.className = 'on'
);

结论

月影老师讲的每一个点都值得我去好好折磨,青训营的旅行才开始就已经感受到的难度不低,前端之路任重道远呀~
各司其职: 各司其职的博客链接
组件封装: 组件封装的博客链接
过程抽象: 你的位置在这里~

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值