JavaScript 函数高阶用法

JavaScript 函数高阶用法

函数柯里化

用途

将函数的参数通过连续调用分开来传

例子

function add(a, b) {
  return a + b;
}

// 执行 add 函数,一次传入两个参数即可
add(1, 2); // 3

// 假设有一个 curry 函数可以做到柯里化
var addCurry = curry(add);
addCurry(1)(2); // 3

实现

function curry(fn, args, holes) {
  length = fn.length;

  args = args || [];

  holes = holes || [];

  return function() {
    var _args = args.slice(0),
      _holes = holes.slice(0),
      argsLen = args.length,
      holesLen = holes.length,
      arg,
      i,
      index = 0;

    for (i = 0; i < arguments.length; i++) {
      arg = arguments[i];
      // 处理类似 fn(1, _, _, 4)(_, 3) 这种情况,index 需要指向 holes 正确的下标
      if (arg === _ && holesLen) {
        index++;
        if (index > holesLen) {
          _args.push(arg);
          _holes.push(argsLen - 1 + index - holesLen);
        }
      }
      // 处理类似 fn(1)(_) 这种情况
      else if (arg === _) {
        _args.push(arg);
        _holes.push(argsLen + i);
      }
      // 处理类似 fn(_, 2)(1) 这种情况
      else if (holesLen) {
        // fn(_, 2)(_, 3)
        if (index >= holesLen) {
          _args.push(arg);
        }
        // fn(_, 2)(1) 用参数 1 替换占位符
        else {
          _args.splice(_holes[index], 1, arg);
          _holes.splice(index, 1);
        }
      } else {
        _args.push(arg);
      }
    }
    if (_holes.length || _args.length < length) {
      return curry.call(this, fn, _args, _holes);
    } else {
      return fn.apply(this, _args);
    }
  };
}

var _ = {};

var fn = curry(function(a, b, c, d, e) {
  console.log([a, b, c, d, e]);
});

// 验证 输出全部都是 [1, 2, 3, 4, 5]
fn(1, 2, 3, 4, 5);
fn(_, 2, 3, 4, 5)(1);
fn(1, _, 3, 4, 5)(2);
fn(1, _, 3)(_, 4)(2)(5);
fn(1, _, _, 4)(_, 3)(2)(5);
fn(_, 2)(_, _, 4)(1)(3)(5);

偏函数

用途

在多次调用某个函数时,将函数的公共参数进行封装,返回一个新的函数

例子

function add(a, b) {
  return a + b;
}

// 执行 add 函数,一次传入两个参数即可
add(1, 2); // 3

// 假设有一个 partial 函数可以做到局部应用
var addOne = partial(add, 1);

addOne(2); // 3
addOne(3); // 4

实现

var _ = {};

function partial(fn) {
  var args = [].slice.call(arguments, 1);
  return function() {
    var position = 0,
      len = args.length;
    for (var i = 0; i < len; i++) {
      args[i] = args[i] === _ ? arguments[position++] : args[i];
    }
    while (position < arguments.length) args.push(arguments[position++]);
    return fn.apply(this, args);
  };
}

惰性函数

用途

在多次调用某个函数时,只返回第一次调用的结果,类似缓存,原理是重写函数

实现

function addEvent(type, el, fn) {
  if (window.addEventListener) {
    addEvent = function(type, el, fn) {
      el.addEventListener(type, fn, false);
    };
  } else if (window.attachEvent) {
    addEvent = function(type, el, fn) {
      el.attachEvent("on" + type, fn);
    };
  }
}

函数组合

用途

在需要对某一个值进行多个函数的过滤时,可以使用函数组合

例子

var toUpperCase = function(x) {
  return x.toUpperCase();
};
var hello = function(x) {
  return "HELLO, " + x;
};

var greet = function(x) {
  return hello(toUpperCase(x));
};

greet("kevin");

实现

// 需求:输入 'kevin daisy kelly',返回 'K.D.K'

// 非 pointfree,因为提到了数据:name
var initials = function(name) {
  return name
    .split(" ")
    .map(compose(toUpperCase, head))
    .join(". ");
};

// pointfree
// 先定义基本运算
var split = curry(function(separator, str) {
  return str.split(separator);
});
var head = function(str) {
  return str.slice(0, 1);
};
var toUpperCase = function(str) {
  return str.toUpperCase();
};
var join = curry(function(separator, arr) {
  return arr.join(separator);
});
var map = curry(function(fn, arr) {
  return arr.map(fn);
});

var initials = compose(join("."), map(compose(toUpperCase, head)), split(" "));

initials("kevin daisy kelly");

函数记忆

用途

某个函数在多次调用时,如果参数没变,直接拿缓存下来的数据

例子

function add(a, b) {
  return a + b;
}

// 假设 memoize 可以实现函数记忆
var memoizedAdd = memoize(add);

memoizedAdd(1, 2); // 3
memoizedAdd(1, 2); // 相同的参数,第二次调用时,从缓存中取出数据,而非重新计算一次

实现

var memoize = function(func, hasher) {
  var memoize = function(key) {
    var cache = memoize.cache;
    var address = "" + (hasher ? hasher.apply(this, arguments) : key);
    if (!cache[address]) {
      cache[address] = func.apply(this, arguments);
    }
    return cache[address];
  };
  memoize.cache = {};
  return memoize;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

易风920

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值