Динамически создавать метод из строки в ES6 javascript (не браузер)

В коде JavaScript у меня есть строка, которая определяет путь свойства внутри объекта. Например

var def = "contact.email"

Как я могу получить следующую функцию из этой строки?

o => o.contact.email

Так что я могу использовать его следующим образом:

var person = {
    name: 'Test',
    contact: { email: 'test@test.test' }
}

var emailGetter = MagicCompileFunction('contact.email');

var email = emailGetter(person);
// here, email should hold the value of person.contact.email

Строка пути неизвестна во время компиляции. Он также может быть предоставлен пользователем.

Решение должно работать и в не браузерной среде (где нет window объект), например, в javascript на стороне сервера NodeJS.

Я знаю, что одним из решений было бы создание универсального метода, который принимает объект и строку в качестве аргументов (valueGetter(person, "contact.email") например), где строка определяет путь внутри объекта, а затем разбивает строку на каждую точку '.' и следуйте по пути на объекте. Но я не хочу, чтобы этот алгоритм выполнялся при каждом вызове getter функция. Мне нужен динамически скомпилированный метод, который дал бы мне окончательный метод получения, который бы немедленно обратился к желаемому (подчиненному) свойству.

4 ответа

Решение

Вы можете добиться этого с помощью конструктора функций

var person = {
    name: 'Test',
    contact: { email: 'test@test.test' }
}
var maginFunction = (def) => new Function('o','return o.'+ def);

var emailGetter = maginFunction('contact.email');

var email = emailGetter(person);
console.log(email);

Чуть больше ES6, чем ответ Арчера:

function MagicCompileFunction(mapping) {
 return (obj => mapping.split(".").reduce((curr, name) => curr[name], obj));
}

var person = {
    name: "Test",
    contact: {
  email: "test@test.test"
 }
}

var emailGetter = MagicCompileFunction("contact.email");
var email = emailGetter(person);

var nameGetter = MagicCompileFunction("name");
var name = nameGetter(person);

console.log(email);
console.log(name);

Мне нравится вопрос, поэтому я нашел решение. Это должно делать то, что вы просите, без необходимости использования eval...

function MagicCompileFunction(mapping) {
 mapping = mapping.split(".");
 return (function(obj) {
  var result = obj;
  for (var idx in mapping) {
   result = result[mapping[idx]];
  }
  return result;
 });
}

var person = {
    name: "Test",
    contact: {
  email: "test@test.test"
 }
}

var emailGetter = MagicCompileFunction("contact.email");
var email = emailGetter(person);

var nameGetter = MagicCompileFunction("name");
var name = nameGetter(person);

console.log(email);
console.log(name);

MagicCompileFunction() возвращает функцию, которая заполнена отображением, которое вы используете при создании объекта-получателя. Затем вы можете передать любому человеку в этот объект, чтобы вернуть соответствующие данные.

Вы можете динамически обращаться к свойствам вложенного объекта просто следующим образом;

function dynPropAcc(o,s){
  return s.split(".")
          .reduce((p,q,i) => i-1 ? p[q] : o[p][q]);
}

var def = "contact.email.2",
    obj = {contact: {name: "John", email: { 1: "john@x.com", 2: "john@y.com"}}};

console.log(dynPropAcc(obj,def));

Другие вопросы по тегам