Поиск альтернативы eval (), когда имя узла / атрибута является переменной / параметром - PullRequest
1 голос
/ 05 марта 2019

Понятно, что когда атрибут (например, id ) существует / определяется в скрипте, мы должны использовать obj[id], а не eval('obj.' + id). Тем не менее, я еще не нашел решения для случая, когда имя атрибута само по себе является переменной и не определено - например, при получении в качестве параметра. В моем случае на сервере есть файл node.js, который получает объект JSON requestData , отправляемый клиентом через socket.io. requestData содержит пару ключ / значение: requestData.key - это массив имен узлов, которые составляют путь JSON к элемент, а requestData.val - это значение, которое будет сохранено в этом элементе.

В серверном скрипте есть определенный объект JSON с именем root , который содержит информацию, относящуюся к приложению, например:

"root": {
  "pages": {
    "TM1010": {
      "appId": "TM1010",
      "componentName": "UserTasksPage"
    },
    "TM1020": {
      "appId": "TM1020",
      "componentName": "UsersPage"
    }
  }
}

Если бы клиент отправил запрос на обновление элемента - например, для изменения значения root.pages.TM1010.componentName - это то, как он будет отправлен от клиента:

let requestData = {'key': ['pages', 'TM1010', 'componentName'], 'val': newComponentName};
this.socket.emit('changeData', requestData);

А вот как он принимается и выполняется на сервере:

socket.on('changeData', (requestData) => {
  var str = 'root'
  var key = requestData.key
  var len = key.length;
  for (var i = 0; i < len; i++) {
   str = str + '["' + key[i] + '"]'
  }
  str = str + '=requestData.val'
  eval(str)
});

Так что то, что выполняется в конце (значение str ), равно:

root["pages"]["TM1010"]["componentName"]=requestData.val

Как это можно сделать без eval()?

Как я уже говорил, я не знаю названий тех элементов, которые будут отправлены с клиента. Все, что у меня есть на сервере, - это один объект JSON с именем «root», и я хочу постоянно добавлять / обновлять его по мере получения данных от клиента. Я пробовал решения, основанные на JEXL или Mathjs, но, похоже, не работает для этого типа случая.

1 Ответ

1 голос
/ 05 марта 2019

Вы можете уменьшить ключи, взяв объект и присвоив значение последнему ключу.

const
    setValue = (object, keys, value) => {
        var path = keys.slice(),
            last = path.pop();
        path.reduce((o, k) => o[k], object)[last] = value;
    };

var data = { root: { pages: { TM1010: { appId: "TM1010", componentName: "UserTasksPage" }, TM1020: { appId: "TM1020", componentName: "UsersPage" } } } },
    requestData = { key: ['pages', 'TM1010', 'componentName'], val: 'newComponentName' };

setValue(data.root, requestData.key, requestData.val);

console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
...