Как создать экзистенциальный оператор в стиле CoffeeScript в JavaScript?

CoffeeScript превращаетсяuser?.id в

if (typeof user !== "undefined" && user !== null) {
   user.id;
}

Можно ли создать функцию JavaScriptexists что бы сделать что-то подобное? то есть

exists(user).id

приведет к либоuser.id или жеnull

Было бы проще, если бы функция принимала другой параметр, т.е.exists(user, 'id')но это невыглядит так хорошо.

 tusharmath17 окт. 2015 г., 06:59
Оформить заказ функции Лодаш.
 Qantas 94 Heavy27 июн. 2013 г., 14:55
Вы'у меня есть проблема сuser не определяется (отличается от значенияundefined), где это победилотакое же поведение. Вы могли бы просто объявить что-то вродеvar user; ради этого, тогда этобыло бы хорошо, но это создает немало беспорядка.
 millimoose27 июн. 2013 г., 13:24
@Zeta Не совсем, так как доступ к несуществующему свойству объекта возвращаетundefined вместо того, чтобы потерпеть неудачу, что должно быть достаточно хорошо.
 Zeta27 июн. 2013 г., 13:19
Для этого понадобятся универсальные геттеры (definegetter(o, function(property){...})которые, если я не ошибаюсь, не являются частью JavaScript 'спецификация.
 millimoose27 июн. 2013 г., 13:24
Самое близкое, о чем я могу подумать, этоfunction exists(obj) { if (obj) return obj; return {}; }но это победилоt обрабатывать неопределенные переменные. Javascript нетт синтаксически расширяемый таким образом.

Ответы на вопрос(3)

Я думаю, что этот функциональный подход может быть интереснымпока в 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

Решение Вопроса

Нет вы можете'не производит такую функцию. Проблема в том, что это:

any_function(undeclared_variable)

выдаст ReferenceError, еслиundeclared_variable нигде не было объявлено. Например, если вы запустите этот автономный код:

function f() { }
f(pancakes);

вы'я получу ReferenceError, потому чтоpancakes нигде не было объявлено. Демо-версия:http://jsfiddle.net/ambiguous/wSZaL/

Тем не менееtypeof оператор может использоваться для чего-то, что не было объявлено, так что это:

console.log(typeof pancakes);

просто войдетundefined в консоли. Демо-версия:http://jsfiddle.net/ambiguous/et2Nv/

Если вы неПримите во внимание возможные ошибки ReferenceErrors, тогда у вас уже есть необходимая функция в вашем вопросе:

function exists(obj, key) {
    if (typeof obj !== "undefined" && obj !== null)
        return obj[key];
    return null; // Maybe you'd want undefined instead
}

или, так как вы ненужно уметь использоватьtypeof здесь для необъявленных переменных вы можете упростить их до:

function exists(obj, key) {
    if(obj != null)
      return obj[key];
    return null;
}

Обратите внимание на изменение,!=undefined == null правда, хотяundefined === null не является.

но заставил меня задуматься над этим решением.

exists = (obj) => obj || {}
exists(nullableObject).propName;
 JasonWoof02 апр. 2018 г., 23:51
Нету. Цитировать coffeescript.org: "Это'Немного сложно проверить наличие переменной в JavaScript. если (переменная)… подходит близко, но не для нуля, пустой строки и false (чтобы назвать только самые распространенные случаи) "

Ваш ответ на вопрос