Как обрабатывать вызывающие функции для данных, которые могут быть неопределенными? - PullRequest
0 голосов
/ 03 октября 2018

Я в основном работаю с React и часто нахожу, что когда я пишу функцию, которая зависит от состояния компонента, мне нужно выполнить проверку, чтобы определить, определена ли часть состояния перед выполнением каких-либо действий.

Например: у меня есть функция, которая использует .map() для циклического перемещения по массиву объектов, извлеченных из базы данных, и генерирует jsx для каждого объекта в массиве.Эта функция вызывается в функции render() моего компонента.При первом вызове render() начальный массив пуст.Это приводит к ошибке, потому что, конечно, первый индекс массива не определен.

Я обошел это, сделав условную проверку, чтобы увидеть, является ли значение массива неопределенным или нет.Этот процесс написания оператора if каждый раз кажется немного неуклюжим, и мне было интересно, есть ли лучший способ выполнить эту проверку или способ полностью ее избежать.

Ответы [ 2 ]

0 голосов
/ 20 февраля 2019

То, что вам на самом деле здесь нужно, называется необязательное сцепление :

obj?.a?.b?.c // no error if a, b, or c don't exist or are undefined/null

?. - это экзистенциальный оператор, который позволяет вам безопасно обращаться к свойствам и не выдает, еслисобственность отсутствует.Однако необязательное сцепление еще не является частью JavaScript , но было предложено, см. Состояние 1 TC39 .

Но, с использованием прокси и Maybe класс, вы можете реализовать необязательную цепочку и возвращать значение по умолчанию, когда цепочка не работает.

Функция wrap() используется для обтекания объектов, к которым вы хотите применить необязательную цепочку.Внутренне wrap создает прокси вокруг вашего объекта и управляет пропущенными значениями с помощью оболочки Maybe.

В конце цепочки вы разворачиваете значение, объединяя в цепочку getOrElse(default) со значением по умолчанию, котороевозвращается, когда цепочка недействительна:

const obj = {
  a: 1,
  b: {
    c: [4, 1, 2]
  },
  c: () => 'yes'
};

console.log(wrap(obj).a.getOrElse(null)) // returns 1
console.log(wrap(obj).a.b.c.d.e.f.getOrElse(null)) // returns null
console.log(wrap(obj).b.c.getOrElse([])) // returns [4, 1, 2]
console.log(wrap(obj).b.c[0].getOrElse(null)) // returns 4
console.log(wrap(obj).b.c[100].getOrElse(-1)) // returns -1
console.log(wrap(obj).c.getOrElse(() => 'no')()) // returns 'yes'
console.log(wrap(obj).d.getOrElse(() => 'no')()) // returns 'no'

wrap(obj).noArray.getOrElse([1]).forEach(v => console.log(v)) // Shows 1
wrap(obj).b.c.getOrElse([]).forEach(v => console.log(v)) // Shows 4, 1, 2

Полный пример:

class Maybe {
  constructor(value) {
    this.__value = value;
  }
  static of(value){
    if (value instanceof Maybe) return value;
    return new Maybe(value);
  }
  getOrElse(elseVal) {
    return this.isNothing() ? elseVal : this.__value;
  }
  isNothing() {
    return this.__value === null || this.__value === undefined;
  }
  map(fn) {  
    return this.isNothing()
      ? Maybe.of(null)
      : Maybe.of(fn(this.__value));
  }
}

function wrap(obj) {
  function fix(object, property) {
    const value = object[property];
    return typeof value === 'function' ? value.bind(object) : value;
  }
  return new Proxy(Maybe.of(obj), {
    get: function(target, property) {
      if (property in target) {
          return fix(target, property);
      } else {
        return wrap(target.map(val => fix(val, property)));
      }
    }
  });
}

const obj = { a: 1, b: { c: [4, 1, 2] }, c: () => 'yes' };

console.log(wrap(obj).a.getOrElse(null))
console.log(wrap(obj).a.b.c.d.e.f.getOrElse(null))
console.log(wrap(obj).b.c.getOrElse([]))
console.log(wrap(obj).b.c[0].getOrElse(null))
console.log(wrap(obj).b.c[100].getOrElse(-1))
console.log(wrap(obj).c.getOrElse(() => 'no')())
console.log(wrap(obj).d.getOrElse(() => 'no')())

wrap(obj).noArray.getOrElse([1]).forEach(v => console.log(v)) // Shows 1
wrap(obj).b.c.getOrElse([]).forEach(v => console.log(v)) // Shows 4, 1, 2
0 голосов
/ 03 октября 2018

Проверьте массив перед использованием карты:

arr && arr.map()

ИЛИ,

arr && arr.length && arr.map() // if you want to map only if not empty array

ИЛИ,

Мы даже можем использовать как это (как прокомментировано devserkan ):

(arr || []).map()

Согласно вашему комментарию:

Хотелось бы, чтобы был безопасный оператор навигации, как в C # (arr? .map ())

Да, очевидно.Это называется необязательное сцепление в JavaScript, который все еще находится в предложении.Если он принят, то вы можете использовать его следующим образом:

arr?.map()

Вы можете увидеть это в staging 1 , для которого вы можете использовать preset stage1


Но очевидно, что кроме длины проверяемого массива ваше требование не будет выполнено:

Это приводит к ошибке, поскольку, конечно, первый индекс массива не определен.

Итак, я предлагаю вам использовать:

arr && arr.length && arr.map()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...