Доступ к вложенным объектам JavaScript с помощью строкового ключа - PullRequest
378 голосов
/ 27 июня 2011

У меня есть такая структура данных:

var someObject = {
    'part1' : {
        'name': 'Part 1',
        'size': '20',
        'qty' : '50'
    },
    'part2' : {
        'name': 'Part 2',
        'size': '15',
        'qty' : '60'
    },
    'part3' : [
        {
            'name': 'Part 3A',
            'size': '10',
            'qty' : '20'
        }, {
            'name': 'Part 3B',
            'size': '5',
            'qty' : '20'
        }, {
            'name': 'Part 3C',
            'size': '7.5',
            'qty' : '20'
        }
    ]
};

И я хотел бы получить доступ к данным, используя эти переменные:

var part1name = "part1.name";
var part2quantity = "part2.qty";
var part3name1 = "part3[0].name";

part1name должно быть заполнено значением someObject.part1.name, которое является «Часть 1». То же самое с part2quantity, который заполнен 60.

Есть ли способ достичь этого с помощью чистого JavaScript или JQuery?

Ответы [ 31 ]

0 голосов
/ 31 мая 2019

Расширение Мохамад Хамудей 'Ответ заполнит недостающие ключи

function Object_Manager(obj, Path, value, Action, strict) 
{
    try
    {
        if(Array.isArray(Path) == false)
        {
            Path = [Path];
        }

        let level = 0;
        var Return_Value;
        Path.reduce((a, b)=>{
            console.log(level,':',a, '|||',b)
            if (!strict){
              if (!(b in a)) a[b] = {}
            }


            level++;
            if (level === Path.length)
            {
                if(Action === 'Set')
                {
                    a[b] = value;
                    return value;
                }
                else if(Action === 'Get')
                {
                    Return_Value = a[b];
                }
                else if(Action === 'Unset')
                {
                    delete a[b];
                }
            } 
            else 
            {
                return a[b];
            }
        }, obj);
        return Return_Value;
    }

    catch(err)
    {
        console.error(err);
        return obj;
    }
}

Пример


obja = {
  "a": {
    "b":"nom"
  }
}

// Set
path = "c.b" // Path does not exist
Object_Manager(obja,path.split('.'), 'test_new_val', 'Set', false);

// Expected Output: Object { a: Object { b: "nom" }, c: Object { b: "test_new_value" } }

0 голосов
/ 11 мая 2019

Я занимаюсь разработкой интернет-магазина с React. Я попытался изменить значения в скопированном объекте состояния, чтобы обновить исходное состояние с ним при отправке. Приведенные выше примеры не работают для меня, потому что большинство из них изменяют структуру копируемого объекта. Я нашел рабочий пример функции для доступа и изменения значений свойств глубоко вложенного объекта: https://lowrey.me/create-an-object-by-path-in-javascript-2/ Вот оно:

const createPath = (obj, path, value = null) => {
  path = typeof path === 'string' ? path.split('.') : path;
  let current = obj;
  while (path.length > 1) {
    const [head, ...tail] = path;
    path = tail;
    if (current[head] === undefined) {
      current[head] = {};
    }
    current = current[head];
  }
  current[path[0]] = value;
  return obj;
};
0 голосов
/ 25 октября 2013

Только что недавно задал тот же вопрос и успешно использовал https://npmjs.org/package/tea-properties, который также set вложенный объект / массивы:

получить:

var o = {
  prop: {
    arr: [
      {foo: 'bar'}
    ]
  }
};

var properties = require('tea-properties');
var value = properties.get(o, 'prop.arr[0].foo');

assert(value, 'bar'); // true

комплект:

var o = {};

var properties = require('tea-properties');
properties.set(o, 'prop.arr[0].foo', 'bar');

assert(o.prop.arr[0].foo, 'bar'); // true
0 голосов
/ 04 декабря 2013

А как насчет этого решения:

setJsonValue: function (json, field, val) {
  if (field !== undefined){
    try {
      eval("json." + field + " = val");
    }
    catch(e){
      ;
    }
  }  
}

И этот, для получения:

getJsonValue: function (json, field){
  var value = undefined;
  if (field !== undefined) {
    try {
      eval("value = json." + field);
    } 
    catch(e){
      ;
    }
  }
  return value;
};

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

0 голосов
/ 22 июня 2018

Работа с Underscore property или propertyOf:

var test = {
  foo: {
    bar: {
      baz: 'hello'
    }
  }
}
var string = 'foo.bar.baz';


// document.write(_.propertyOf(test)(string.split('.')))

document.write(_.property(string.split('.'))(test));
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"></script>

Удачи ...

0 голосов
/ 23 февраля 2018

// (IE9+) Two steps

var pathString = "[0]['property'].others[3].next['final']";
var obj = [{
  property: {
    others: [1, 2, 3, {
      next: {
        final: "SUCCESS"
      }
    }]
  }
}];

// Turn string to path array
var pathArray = pathString
    .replace(/\[["']?([\w]+)["']?\]/g,".$1")
    .split(".")
    .splice(1);

// Add object prototype method
Object.prototype.path = function (path) {
  try {
    return [this].concat(path).reduce(function (f, l) {
      return f[l];
    });
  } catch (e) {
    console.error(e);
  }
};

// usage
console.log(obj.path(pathArray));
console.log(obj.path([0,"doesNotExist"]));
0 голосов
/ 01 ноября 2017

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

function get(obj, str) {
  return str.split(/\.|\[/g).map(function(crumb) {
    return crumb.replace(/\]$/, '').trim().replace(/^(["'])((?:(?!\1)[^\\]|\\.)*?)\1$/, (match, quote, str) => str.replace(/\\(\\)?/g, "$1"));
  }).reduce(function(obj, prop) {
    return obj ? obj[prop] : undefined;
  }, obj);
}
0 голосов
/ 25 октября 2017

Вместо строки можно использовать массив для адресации вложенных объектов и массивов, например: ["my_field", "another_field", 0, "last_field", 10]

Вот пример, который может изменить поле на основе этого представления массива. Я использую что-то подобное вact.js для контролируемых полей ввода, которые изменяют состояние вложенных структур.

let state = {
        test: "test_value",
        nested: {
            level1: "level1 value"
        },
        arr: [1, 2, 3],
        nested_arr: {
            arr: ["buh", "bah", "foo"]
        }
    }

function handleChange(value, fields) {
    let update_field = state;
    for(var i = 0; i < fields.length - 1; i++){
        update_field = update_field[fields[i]];
    }
    update_field[fields[fields.length-1]] = value;
}

handleChange("update", ["test"]);
handleChange("update_nested", ["nested","level1"]);
handleChange(100, ["arr",0]);
handleChange('changed_foo', ["nested_arr", "arr", 3]);
console.log(state);
0 голосов
/ 02 августа 2017

Построение ответа Альнитака:

if(!Object.prototype.byString){
  //NEW byString which can update values
Object.prototype.byString = function(s, v, o) {
  var _o = o || this;
      s = s.replace(/\[(\w+)\]/g, '.$1'); // CONVERT INDEXES TO PROPERTIES
      s = s.replace(/^\./, ''); // STRIP A LEADING DOT
      var a = s.split('.'); //ARRAY OF STRINGS SPLIT BY '.'
      for (var i = 0; i < a.length; ++i) {//LOOP OVER ARRAY OF STRINGS
          var k = a[i];
          if (k in _o) {//LOOP THROUGH OBJECT KEYS
              if(_o.hasOwnProperty(k)){//USE ONLY KEYS WE CREATED
                if(v !== undefined){//IF WE HAVE A NEW VALUE PARAM
                  if(i === a.length -1){//IF IT'S THE LAST IN THE ARRAY
                    _o[k] = v;
                  }
                }
                _o = _o[k];//NO NEW VALUE SO JUST RETURN THE CURRENT VALUE
              }
          } else {
              return;
          }
      }
      return _o;
  };

}

Это также позволяет вам установить значение!

Я создал пакет npm и github с этим

0 голосов
/ 27 июня 2011

Если вам нужно получить доступ к другому вложенному ключу, не зная его во время кодирования (обращаться к ним будет тривиально), вы можете использовать средство доступа к записи массива:

var part1name = someObject['part1']['name'];
var part2quantity = someObject['part2']['qty'];
var part3name1 =  someObject['part3'][0]['name'];

Они эквивалентны точечной записиAccessor и может варьироваться во время выполнения, например:

var part = 'part1';
var property = 'name';

var part1name = someObject[part][property];

эквивалентно

var part1name = someObject['part1']['name'];

или

var part1name = someObject.part1.name;

Я надеюсь, что этот адрес ваш вопрос ...

РЕДАКТИРОВАТЬ

Я не буду использовать строку для поддержки своего рода xpath query для доступа к значению объекта.Так как вам нужно вызвать функцию для анализа запроса и получения значения, я бы следовал по другому пути (не:

var part1name = function(){ return this.part1.name; }
var part2quantity = function() { return this['part2']['qty']; }
var part3name1 =  function() { return this.part3[0]['name'];}

// usage: part1name.apply(someObject);

или, если вас не устраивает метод apply

var part1name = function(obj){ return obj.part1.name; }
var part2quantity = function(obj) { return obj['part2']['qty']; }
var part3name1 =  function(obj) { return obj.part3[0]['name'];}

// usage: part1name(someObject);

Функции короче, понятнее, интерпретатор проверяет их на наличие синтаксических ошибок и т. Д.

Кстати, я чувствую, что простого назначения, выполненного в нужное время, будет достаточно...

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