Lodash cloneDeep с пропуском undefined

1

Я написал функцию customozer, чтобы опустить неопределенные значения объекта с помощью cloneDeepWith. Однако при неизменном возвращении он не рекурсивно копается. Вот мой код:

import { cloneDeepWith, pickBy, omit } from 'lodash';

const obj = {
  a0: true,
  b0: true,
  c0: undefined,
  obj1: {
    a1: true,
    b1: true,
    c1: undefined
  }
};

cloneDeepWith(obj, value => {
    const objWithUndefinedValue = pickBy(obj, (value) => value === undefined);
    const keysWithUndefinedValue = Object.keys(objWithUndefinedValue);
    return omit(obj, keysWithUndefinedValue);
});

Однако после первого возвращения он не рекурсирует. Можно ли это сделать с помощью функции запаса lodash?

Теги:
lodash

2 ответа

2
Лучший ответ

Насколько я знаю, _.cloneDeepWith() customizer немного вводит в заблуждение. Настройщик должен обрабатывать только значения, отличные от объекта. Если он обрабатывает значения объекта, он также должен продолжить рекурсию. Например, вы можете видеть, что при вызове customizer клонирование обрабатывается value.cloneNode(true). Как вы видите, в консоли отображается только body.

const { cloneDeepWith, isObject } = _;

function customizer(value) {
  console.log(value);
  if (_.isElement(value)) {
    return value.cloneNode(true);
  }
}
 
var el = _.cloneDeepWith(document.body, customizer);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Однако, если вы просто настраиваете значения без объекта и возвращаете undefined значения объекта, что побуждает метод обрабатывать их (задокументировано в cloneDeep), он выполняет итерацию всего:

const { cloneDeepWith, isObject, isUndefined } = _;

const obj = {
  a0: true,
  b0: true,
  c0: undefined,
  obj1: {
    a1: true,
    b1: true,
    c1: undefined
  }
};

const result = cloneDeepWith(obj, v => {
  console.log(v);
  
  return isObject(v) ? undefined : 'custom value';
});

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Чтобы решить вашу проблему, вы можете использовать _.transform() рекурсивно, чтобы принимать все значения, которые не undefined:

const { transform, isObject, isUndefined } = _;

const obj = {
  a0: true,
  b0: true,
  c0: undefined,
  obj1: {
    a1: true,
    b1: true,
    c1: undefined
  }
};

const cloneDeepWithoutUndefined = (obj) =>
  transform(obj, (r, v, k) => {
    if(isUndefined(v)) return;
    r[k] = isObject(v) ? cloneDeepWithoutUndefined(v) : v;
  });
  
const result = cloneDeepWithoutUndefined(obj);

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
  • 0
    Ох, интересно, большое спасибо, Ори!
  • 1
    Добро пожаловать :) Я был озадачен таким поведением.
1

Это можно решить с помощью метода рекурсивного преобразования lodash с помощью:

const obj = { a0: true, b0: true, c0: undefined, obj1: { a1: true, b1: true, c1: undefined } };

const cloneMe = (obj) => _.transform(obj, (r, v, k) => 
  _.isUndefined(v) ? null : _.isObject(v) ? r[k] = cloneMe(v) : r[k] = v, {})

console.log(cloneMe(obj))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

Вы также можете сделать это в ES6 только через Object.entries & reduce:

const obj = { a0: true, b0: true, c0: undefined, obj1: { a1: true, b1: true, c1: undefined } };

const cloneMe = (obj) => {
   return Object.entries(obj).filter(([k,v]) => 
      v != undefined).reduce((r,[k,v]) => {
        r[k] = (v instanceof Object) ? cloneMe(v) : v
        return r
   },{})
}

console.log(cloneMe(obj))

Вы можете дополнительно продлить проверку объекта, если instance of Object недостаточно и т.д.

  • 0
    Это очень круто, спасибо за методы es6 и lodash!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню