【若川视野 x 源码共读】第36期 | omit.js 剔除对象中的属性

86 阅读1分钟

1.omit.js原理分析

原理:在不影响原数据下,剔除对象中的属性。先拷贝出来一个对象(浅拷贝),然后进行操作。

function omit(obj, fields) {
  // Object.assign--浅拷贝,第一层数据深拷贝,第二层嵌套数据为浅拷贝
  const shallowCopy = Object.assign({}, obj);
  for (let i = 0; i < fields.length; i += 1) {
    const key = fields[i];
    delete shallowCopy[key];
  }
  return shallowCopy;
}

2.深拷贝和浅拷贝的区别?为啥会有深拷贝和浅拷贝?分别实现的方法是什么?

  1. 浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。 深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。 浅拷贝:只进行一层拷贝,深拷贝就是无限层级的拷贝。
  2. 深拷贝和浅拷贝区别只是针对引用数据类型。
  3. 浅拷贝的实现方式
1. Object.assign() //对非嵌套对象进行深拷贝的方法
`当object只有一层的时候,是深拷贝`
2. Array.prototype.concat() //适合一维数组
let arr = [1, 3, {
   username: 'kobe'
}];
let arr2=arr.concat();
arr2[2].username = 'wade';
console.log(arr);
3. Array.prototype.slice() //适合一维数组
4. for...in 循环遍历赋值
5. 扩展运算符(最常用的方式)

  1. 深拷贝的实现方式
1. JSON.parse(JSON.stringify())
    缺点:
    1. 不能处理函数
    2. 如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式。而不是时间对象
    3. 如果obj里有RegExpError对象,则序列化的结果将只得到空对象
    4. 如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失
    5. 如果obj里有NaNInfinity和-Infinity,则序列化的结果会变成null
    6. JSON.stringify()只能序列化对象的可枚举的自有属性,例如 如果obj中的对象是有构造函数生成的, 则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象constructor
    function Person(name) {
        this.name = name;
        console.log(name)
      }

      const liai = new Person('liai');

      const test = {
        name: 'a',
        date: liai,
      };
      // debugger
      const copyed = JSON.parse(JSON.stringify(test));
      test.name = 'test'
      console.error('ddd', test, copyed)
    7. 如果对象中存在循环引用的情况也无法正确实现深拷贝
    8. 不支持Symbol
2. 手写克隆函数
function isObject(obj) {
  return typeof obj === 'object' && obj !== null;
}
function deepCopy(souce) {
  if (!isObject(souce)) return souce;
  let target = Array.isArray(souce) ? [] : {};
  for( var k in souce) {
    if (souce.hasOwnProperty(k)) {
      if (souce[k] && typeof souce[k] === 'object') {
        target[k] = deepCopy(souce[k]);
      } else {
        target[k] = souce[k];
      }
    }
  }
  return target;
}
1. `上述函数,当数据的层次很深,会栈溢出`2. `循环引用`
  const symbolName = Symbol();
  const obj = {
    objNumber: new Number(1),
    number: 1,
    objString: new String('ss'),
    string: 'stirng',
    objRegexp: new RegExp('\w'),
    regexp: /w+/g,
    date: new Date(),
    function: function () {},
    array: [{a: 1}, 2],
    [symbolName]: 111
  }
  obj.d = obj;

  const isObject = obj => obj !== null && (typeof obj === 'object' || typeof obj === 'function');
  const isFunction = obj => typeof obj === 'function'
  function deepClone (obj, hash = new WeakMap()) {
    if (hash.get(obj)) {
      // 环处理
      return hash.get(obj);
    }
    if (!isObject(obj)) {
      return obj;
    }

    if (isFunction(obj)) {
      // function返回原引用
      return obj;
    }

    let cloneObj;

    const Constructor = obj.constructor;

    switch (Constructor) {
      case Boolean:
      case Date:
        return new Date(+obj);
      case Number:
      case String:
      case RegExp:
        return new Constructor(obj);
      default:
        cloneObj = new Constructor();
        hash.set(obj, cloneObj);
    }

    [...Object.getOwnPropertyNames(obj), ...Object.getOwnPropertySymbols(obj)].forEach(k => {
      cloneObj[k] = deepClone(obj[k], hash);
    })
    return cloneObj;
  }
  const o = deepClone(obj)

3. 函数库lodash
var _ = require('lodash');
var obj1 = {
   a: 1,
   b: { f: { g: 1 } },
   c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);
4. $.extend([deep],target,object1,...)

3.如果传入的第二个参数不是数组呢?

解决方法: 将任何数据转换成数组 arrify---33期源码分析中使用。

4.可以通过其他方式实现,改造此函数,多些思考。

function omit(obj, fields) {
  // Object.assign--浅拷贝,第一层数据深拷贝,第二层嵌套数据为浅拷贝
  const shallowCopy = Object.assign({}, obj);
  // const shallowCopy = {...obj}; ---浅拷贝中的方法都可以
  let arr=[];
  if(Array.isArray(fields)){
   arr=fields
  }else{
   arr=arrify(fields)
  }
  //数组循环的三种方法:for..in forEach for
  for (let i = 0; i < fields.length; i += 1) {
    const key = fields[i];
    delete shallowCopy[key];
  }
  return shallowCopy;
}

5.感悟

第一次在掘金上发表笔记,原来一直在本地做一些记录,希望有错误及时指出,大家一起努力。