高阶函数

2019/11/06 javascript

昨天学完,今天写笔记,嗯…好习惯

1、高阶函数

函数的本质就是回调。

高阶函数具有下面两个特征,包含任意一个就可以被称之为高阶函数。

一个函数的参数是一个函数

一个函数的返回值是一个函数

2、AOP编程

AOP编程就是切片编程:把核心抽离出来,在核心的基础上增加功能。

假设:我们需要一个函数say

  const say = ()=>{
    console.log('我是say函数');
  }

但是我们需要在say之前做点什么,于是我们就需要这样say.beform()

beform可能任何函数都会调用。所以我们需要把它注册到原型上,然后它接收一个函数,返回一个函数,(高阶函数的特征)

  Function.prototype.before = function(beforeFn) {
    return () => { // 箭头函数没有this
      beforeFn(); // before
      this();  // 这个this是当前调用的函数 -- say
    }
  }

我们调用一下它。

  const newSay = say.before(()=>{
    console.log('hi');
  })
  newSay(); // hi  我是say函数

如果我们需要传参,把想说的话传进去。

  newSay(1,2,3);

需要传参的完整代码

  Function.prototype.before = function(beforeFn) {
    return (...arg) => { // 箭头函数没有this
      beforeFn(...arg); // before
      this(...arg);  // 这个this是当前调用的函数 -- say
    }
  }

  const say = (...arg)=>{
    console.log(arg)
  }

  const newSay = say.before((...arg)=>{
    console.log(arg);
  })

  newSay(1,2,3);

解释:

  1. 在原型上定义一个方法,接收一个函数,返回一个函数。
  2. 当调用的时候,nweSay就是before返回的那个函数,所以传的参数也到了before里面的函数上
  3. 执行newSay就是执行before里面的函数,然后就执行了 beforeFn, this()
  4. 由于是箭头函数,没有this,所以在函数里面调用this就是调用say函数。
  5. 会打印出两组[1,2,3]

3、使用AOP实现一个类型判断函数

类型判断使用Object.prototype.toString.call

所以我们需要一个大概这样的函数,假设判断是否为数字,因为是高阶函数,所以要返回一个函数。

  const checkType = ()=>{
     return (content)=>{
       return Object.prototype.toString.call(content) === `[object number]`
     }
   }

因为函数要通用,所以我们把number变成变量

  const checkType = (type)=>{
     return (content)=>{
      return Object.prototype.toString.call(content) === `[object ${type}]`
    }
  }

调用一下

  const isNumber = checkType2('Number');
  console.log(isNumber(123));  // true

这样就可以了,但是每次都需要传一个类型,用户万一传错了,或者怎样的不太友好,所以我们需要自己把类型定义好,由用户去调用方法,比如数字就调用isNumber

先定义一个类型数组,然后去生成方法名。

  let types = ['Number', 'String', 'Boolean', 'Array'];
  let utils = {};

  types.forEach(type => {
    utils['is' + type] = checkType(type);
  })

这样各种类型的isXXX方法就生成好了。

然后就可以调用了

  console.log(utils.isNumber(123))
  console.log(utils.isString('111'))
  console.log(utils.isArray([1,2,3]))

完整代码:

  const checkType = (type)=>{
    return (content)=>{
      return Object.prototype.toString.call(content) === `[object ${type}]`
    }
  }

  let types = ['Number', 'String', 'Boolean', 'Array'];
  let utils = {};

  types.forEach(type => {
    utils['is' + type] = checkType(type);
  })

  console.log(utils.isNumber(123))
  console.log(utils.isString('111'))
  console.log(utils.isArray([1,2,3]))

4、柯里化

将一个函数拆分成多个小函数来处理参数就是柯里化,柯里化的好处:可以保留参数。

假设我们要实现下面代码的功能,需要把函数柯里化。

  nst add = (a, b, c, d, e) => {
    return a + b + c + d + e;
  };
  let r = curring(add)(1)(2)(3)(4,5);
  console.log(r)

我们需要把每次的参数存起来,柯里化会用到回调,所以需要有判断条件,我们要判断参数都拆分完了,然后就不继续回调了,就执行add方法, 我们需要下面的函数

  const curring = (fn,arr = [])=>{
    // fn 就是add   arr 作参数收集
    let len = fn.length;  // 函数参数的长度就是函数的长度
    return (...args)=>{
      arr = arr.concat(args);
      if(arr.length < len){
        return curring(fn, arr);
      }
      return fn(...arr)
    }
  }

  let r = curring(add)(1)(2)(3)(4,5);
  console.log(r)

解释:

  1. 顶一个函数,接受原函数和参数,
  2. 由于我们需要一个条件进行判断,所以我们用原函数的长度作为判断(函数的参数的数量就是函数的长度)。
  3. 定义一个数组,用作参数收集,最后都放到add里面去.
  4. 判断收集到的数组的长度是否小于函数的长度,如果小于则继续回调,否则执行addaddfn

5、柯里化类型判断函数

  const checkType = (type)=>{
    return (content)=>{
      return Object.prototype.toString.call(content) === `[object ${type}]`
    }
  }

  const curring = (fn,arr = [])=>{
    let len = fn.length; 
    return (...args)=>{
      arr = arr.concat(args);
      if(arr.length < len){
        return curring(fn, arr);
      }
      return fn(...arr)
    }
  }

  let types = ['Number', 'String', 'Boolean', 'Array'];
  let utils = {};

  types.forEach(type => {
    utils['is' + type] = curring(checkType)(type);
  })

  console.log(utils.isNumber(123))
  console.log(utils.isString('111'))
  console.log(utils.isArray([1,2,3]))

解释:

  1. 主要解释这一点 utils['is' + type] = curring(checkType)(type);
  2. 执行curring的时候,把checkType传进去,并且把type传进去
  3. 由于只有一个参数,函数长度也是一个,所以直接就执行checkType了,并且把type传递给了checkType
  4. 执行checkType,把返回的函数赋值给utils['is' + type]

Search

    Table of Contents