合并默认参数

1,041 阅读2分钟

背景

在日常开发中,有时候我们会给定一些默认的参数,这样使用者就可以少传一些参数,降低某块功能的使用难度。以下是某个场景:

const defaultOptions = {
    name: '蔡徐坤',
    actions: {
        sing: true,
        jump: true,
        rap: true,
    }
}

const myOptions = {
    name: '周杰伦',
    actions: {
        jump: false,
        lol: true
    }
}

const result = fn(myOptions, defaultOptions)
console.log(result)
/*
{
    name: '周杰伦',
    actions: {
        sing: true,
        jump: false,
        rap: true,
        lol: true
    }
}
*/

看出来这个fn函数做了什么没?用户提供了属性的话就覆盖,否则使用缺省数据。今天我们就来实现这个fn函数

lodash

lodash这个库的使用率还是很高的,很多开发者多多少少用过。其提供了丰富多彩的功能函数,基本覆盖了我们的日常开发任务。很有名气的有:防抖 debounce节流 throttle深拷贝 cloneDeep等。

同时,lodash也提供了解决我们今天问题的函数:defaultsDeep。 用起来,和我们上文的fn也基本一致,下面是官方的一个实例:

_.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } });
// => { 'a': { 'b': 2, 'c': 3 } }

用法是一模一样,有兴趣的同学可以看看lodash是怎么实现的。我们接着往下看,看看我们是怎么实现的

javascriptweekly 474期

javascriptweekly 474期中向我们推荐了一个小工具,也是为了解决这个问题,他就是我们今天的主角defu,其貌不扬的仓库,地址。我们来看看这位jsless(作者)是怎么完成的。

源码的量还是很少的,我们直接开门见山,打开lib/index.js

function isObject (val) {
  return val !== null && typeof val === 'object' && !Array.isArray(val)
}

function defu (_obj, _defaults) {
  if (!isObject(_obj)) {
    return defu({}, _defaults)
  }

  if (!isObject(_defaults)) {
    return defu(_obj, {})
  }

  var obj = Object.assign({}, _defaults)
  Object.keys(_obj).forEach(function (key) {
    if (key === '__proto__' || key === 'constructor') {
      return
    }

    var val = _obj[key]

    if (val === null) {
      return
    }

    if (isObject(val) && isObject(obj[key])) {
      obj[key] = defu(val, obj[key])
    } else {
      obj[key] = val
    }
  })
  return obj
}

module.exports = defu

源码开头定义了个判断是否是对象的函数isObject,不为null,typeof为object,不为数组。哈哈,在js中,很平常的一个判断是否为对象的功能函数。

defu函数的核心思想就是使用递归去"分解"_obj中的对象属性,直到成为基本数据类型。

var obj = Object.assign({}, _defaults) 这里定义的obj变量能保证_defaults不会被修改,防止污染数据源。在迭代的过程中不停的修改obj,最后return出去。

obj[key] = defu(val, obj[key])这行代码是本库的核心代码,一字千金。通过递归defu函数不停地分解_obj

总结

总体而言,这个库还是很小的,缺乏一些边缘场景的考虑。但是通过其,学习下怎么去使用递归思想解决日常开发中的问题,还是很值得看看的。有兴趣的同学可以去看看_.defaultsDeep的实现,对比下,还是能看出lodash的全面和成熟!