Есть ли способ использовать функцию доступа для определения свойства объекта в JS?

#javascript #object #functional-programming

Вопрос:

У меня есть два входа:

 data = {"year": 2021}
valueAccessor = (d) => d["year"];
 

Эти два ввода могут быть динамическими, поэтому я не знаю, что будет в объекте или функции.

Я хочу создать новый объект и задать значения для этого объекта с помощью функции доступа. Есть ли способ сделать это?

 output = {}
output = definePropertyUsingFunction(output, valueAccessor, newValue)
 

Комментарии:

1. Нет, это не так…

Ответ №1:

Короткий ответ — «нет». Но…

Если вы находитесь в какой-то контролируемой среде обучения, есть некоторые вещи, которые вы могли бы попробовать.

Если вы точно знаете, что:

  • Ваша getter функция чиста (без побочных эффектов), и
  • Ваша getter функция всегда обращается к 1 свойству,

ты мог бы

  • Используйте Proxy функцию, которая отслеживает доступ к свойствам
  • Сделайте вызов getter , чтобы вызвать его (опять же, если это чистая функция, она не должна иметь никаких побочных эффектов).
  • Запишите значение в зарегистрированное свойство

Вот доказательство концепции:

 const data = { year: 2000, month: 1, day: 28 };

const getYear = obj => obj.year;
const getMonth = obj => obj.month;
const toString = obj => `${obj.year}/${obj.month}/${obj.day}`;

const writeViaSimpleGetter = (obj, value, getter) => {
  let propName = null;
  
  const proxy = new Proxy(obj, {
    get: (target, key) => {
      if (propName) throw "Multiple properties accessed";
      propName = key;
    }
  });
  
  // Call the getter
  getter(proxy);
  
  if (!propName) throw "No property accessed";
  
  return { ...obj, [propName]: value };
}

// Simple getters work:
console.log(
  writeViaSimpleGetter(data, 2021, getYear)
)

console.log(
  writeViaSimpleGetter(data, 12, getMonth)
)

// This throws:
try {
  console.log(
    writeViaSimpleGetter(data, "oops", toString)
  )
} catch(e) { console.log("ERROR:", e) }

// This also throws:
try {
  console.log(
    writeViaSimpleGetter(data, "oops", () => {})
  )
} catch(e) { console.log("ERROR:", e) }