【会员源码共读】01 - omit.js

163 阅读1分钟

「我正在参与掘金会员专属活动-源码共读第一期,点击参与

准备工作

git clone <https://github.com/benjycui/omit.js.git>

cd ./omit.js && code .

npm i

# 查看lodash 中的 omit
git clone <https://github.com/lodash/lodash.git>

cd ./lodash && code .

# 切换到 1.0.0 版本
git checkout 1.0.0

omit.js 分析

function omit(obj, fields) {
  // eslint-disable-next-line prefer-object-spread
  const shallowCopy = Object.assign({}, obj); // #1
  for (let i = 0; i < fields.length; i += 1) {
    const key = fields[i];
    delete shallowCopy[key]; // #2
  }
  return shallowCopy; // #3
}

export default omit;
  1. 使用 Object.assign() 创建一个 obj 的浅拷贝

    1. Object.assign() 拷贝的是属性值,如果属性值是对象,那么拷贝的就是对象的引用
    const obj = {
        "a": 1,
        "b": 2,
        "c": {
            "c1": 1,
            "c2": 2
        }
    }
    
    const obj2 = omit(obj,['a'])
    
    obj.c === obj2.c // true
    
  2. 遍历 fields ,删除浅拷贝后的 obj 对象中的属性

  3. 最后返回该对象

lodash中的 omit

最新的实现很多代码都是处理各种边界情况和深浅拷贝的,看起来实在无聊,所以本次阅读的是 1.0.0 中的实现

/**
   * Creates a shallow clone of `object` excluding the specified properties.
   * Property names may be specified as individual arguments or as arrays of
   * property names. If a `callback` function is passed, it will be executed
   * for each property in the `object`, omitting the properties `callback`
   * returns truthy for. The `callback` is bound to `thisArg` and invoked
   * with three arguments; (value, key, object).
   *
   * @static
   * @memberOf _
   * @category Objects
   * @param {Object} object The source object.
   * @param {Function|String} callback|[prop1, prop2, ...] The properties to omit
   *  or the function called per iteration.
   * @param {Mixed} [thisArg] The `this` binding of `callback`.
   * @returns {Object} Returns an object without the omitted properties.
   * @example
   *
   * _.omit({ 'name': 'moe', 'age': 40 }, 'age');
   * // => { 'name': 'moe' }
   *
   * _.omit({ 'name': 'moe', 'age': 40 }, function(value) {
   *   return typeof value == 'number';
   * });
   * // => { 'name': 'moe' }
   */
function omit(object, callback, thisArg) { // #1
    var isFunc = typeof callback == 'function',
        result = {};

    if (isFunc) {
      callback = createCallback(callback, thisArg); // #2
    } else {
      var props = concat.apply(arrayRef, arguments); // #3
    }
    forIn(object, function(value, key, object) { // #4
      if (isFunc
            ? !callback(value, key, object)
            : indexOf(props, key, 1) < 0
          ) {
        result[key] = value;
      }
    });
    return result; // #5
  }
  1. 1.0.0设计成可以传入字符串,也可以传入函数

  2. 如果传入的是函数, 执行createCallback ,生成一个重新指定了 this 指向的函数

  3. 如果传入的是字符串,则收集成数组,这里使用 concat 复制arguments ,其实就是简略实现了es6 中的 收缩运算符,不得不佩服其实力,走在了 es6 前

    //现在只需使用...运算符即可
    function omit(obj,...values)
    
  4. 和本次仓库的实现正相反,遍历的是传入的源对象,而不是要剔除的属性集合,忽略掉要剔除的属性,收集要保留的,放入 result

  5. 最后返回 result

重写 omit.js

按照 lodash 的思路,遍历源对象, 而不是遍历要剔除的属性

function omit(obj,props){
    const result = {}
    Object.keys(obj).map(key=>{
        if(!props.includes(key)){
            result[key] = obj[key]
        }
    })
    return result
}

改造一行代码,就是 lodash 的 pick 函数了(反向版 omit

function pick(obj,props){
    const result = {}
    Object.keys(obj).map(key=>{
        if(props.includes(key)){ // 把取反去掉
            result[key] = obj[key]
        }
    })
    return result
}

const object = { 'a': 1, 'b': '2', 'c': 3 };
 
pick(object, ['a', 'c']);
// => { 'a': 1, 'c': 3 }

最后

本次 omit.js 源码阅读到此结束,我知道本次仓库还有其他可挖掘的部分比如 npm依赖 ,测试用例 等,后续文章再继续看吧

<完>