Dostęp do zagnieżdżonych obiektów i tablic JavaScript za pomocą ścieżki łańcuchowej

Mam taką strukturę danych:

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'
        }
    ]
};

I chciałbym uzyskać dostęp do danych za pomocą tej zmiennej:

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

Nazwa Part1 powinna być wypełniona wartością someObject.part1.name, która jest "Part 1". To samo z part2quantity, który wypełniony 60.

Czy w ogóle można to osiągnąć za pomocą czystego javascript lub JQuery?

Author: JSK NS, 2011-06-27

30 answers

Właśnie zrobiłem to na podstawie jakiegoś podobnego kodu, który już miałem, wygląda na to, że działa:

Object.byString = function(o, s) {
    s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
    s = s.replace(/^\./, '');           // strip a leading dot
    var a = s.split('.');
    for (var i = 0, n = a.length; i < n; ++i) {
        var k = a[i];
        if (k in o) {
            o = o[k];
        } else {
            return;
        }
    }
    return o;
}

Usage::

Object.byString(someObj, 'part3[0].name');

Zobacz działające demo na http://jsfiddle.net/alnitak/hEsys/

EDIT niektórzy zauważyli, że ten kod spowoduje błąd, jeśli przekazany zostanie ciąg znaków, w którym większość indeksów po lewej stronie nie odpowiada poprawnie zagnieżdżonemu wpisowi wewnątrz obiektu. Jest to słuszna troska, ale IMHO najlepiej zająć się blokiem try / catch podczas wywoływania, zamiast mieć to funkcja po cichu zwraca undefined dla nieprawidłowego indeksu.

 565
Author: Alnitak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-10 13:40:11

Jest to teraz obsługiwane przez lodash przy użyciu _.get(obj, property). Zobacz https://lodash.com/docs#get

Przykład z docs:

var object = { 'a': [{ 'b': { 'c': 3 } }] };

_.get(object, 'a[0].b.c');
// → 3

_.get(object, ['a', '0', 'b', 'c']);
// → 3

_.get(object, 'a.b.c', 'default');
// → 'default'
 207
Author: Ian Walker-Sperber,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-08 20:59:00

Jest to rozwiązanie, którego używam:

function resolve(path, obj=self, separator='.') {
    var properties = Array.isArray(path) ? path : path.split(separator)
    return properties.reduce((prev, curr) => prev && prev[curr], obj)
}

Przykładowe użycie:

// accessing property path on global scope
resolve("document.body.style.width")
// or
resolve("style.width", document.body)

// accessing array indexes
// (someObject has been defined in the question)
resolve("part3.0.size", someObject) // returns '10'

// accessing non-existent properties
// returns undefined when intermediate properties are not defined:
resolve('properties.that.do.not.exist', {hello:'world'})

// accessing properties with unusual keys by changing the separator
var obj = { object: { 'a.property.name.with.periods': 42 } }
resolve('object->a.property.name.with.periods', obj, '->') // returns 42

// accessing properties with unusual keys by passing a property name array
resolve(['object', 'a.property.name.with.periods'], obj) // returns 42

Ograniczenia:

  • nie można używać nawiasów ([]) dla indeksów tablicowych-chociaż określanie indeksów tablic między tokenem separatora (np. .) działa dobrze, jak pokazano powyżej.
 198
Author: speigg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-15 00:59:02

ES6 : tylko jedna linia w Vanila JS (zwraca null, jeśli nie znajduje się zamiast błędu):

'path.string'.split('.').reduce((p,c)=>p&&p[c]||null, MyOBJ)

Lub przykład:

'a.b.c'.split('.').reduce((p,c)=>p&&p[c]||null, {a:{b:{c:1}}})

Z opcjonalnym operatorem łańcuchowym :

'a.b.c'.split('.').reduce((p,c)=>p?.[c], {a:{b:{c:1}}})

Dla gotowej do użycia funkcji, która rozpoznaje również liczbę false, 0 i ujemną i przyjmuje wartości domyślne jako parametr:

const resolvePath = (object, path, defaultValue) => path
   .split('.')
   .reduce((o, p) => o ? o[p] : defaultValue, object)

Przykład użycia:

resolvePath(window,'document.body') => <body>
resolvePath(window,'document.body.xyz') => undefined
resolvePath(window,'document.body.xyz', null) => null
resolvePath(window,'document.body.xyz', 1) => 1

Bonus:

To set a path (Requested by @rob-gordon) you can użycie:

const setPath = (object, path, value) => path
   .split('.')
   .reduce((o,p,i) => o[p] = path.split('.').length === ++i ? value : o[p] || {}, object)

Przykład:

let myVar = {}
setPath(myVar, 'a.b.c', 42) => 42
console.log(myVar) => {a: {b: {c: 42}}}

tablica dostępowa z []:

const resolvePath = (object, path, defaultValue) => path
   .split(/[\.\[\]\'\"]/)
   .filter(p => p)
   .reduce((o, p) => o ? o[p] : defaultValue, object)

Przykład:

const myVar = {a:{b:[{c:1}]}}
resolvePath(myVar,'a.b[0].c') => 1
resolvePath(myVar,'a["b"][\'0\'].c') => 1
 125
Author: Adriano Spadoni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-09 19:05:19

Musiałbyś sam przeanalizować łańcuch:

function getProperty(obj, prop) {
    var parts = prop.split('.');

    if (Array.isArray(parts)) {
        var last = parts.pop(),
        l = parts.length,
        i = 1,
        current = parts[0];

        while((obj = obj[current]) && i < l) {
            current = parts[i];
            i++;
        }

        if(obj) {
            return obj[last];
        }
    } else {
        throw 'parts is not valid array';
    }
}

Wymagało to również zdefiniowania indeksów tablic z notacją kropkową:

var part3name1 = "part3.0.name";

Ułatwia to parsowanie.

DEMO

 66
Author: Felix Kling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-04 13:46:31

Działa również dla tablic / tablic wewnątrz obiektu. Obrona przed nieprawidłowymi wartościami.

/**
 * Retrieve nested item from object/array
 * @param {Object|Array} obj
 * @param {String} path dot separated
 * @param {*} def default value ( if result undefined )
 * @returns {*}
 */
function path(obj, path, def){
    var i, len;

    for(i = 0,path = path.split('.'), len = path.length; i < len; i++){
        if(!obj || typeof obj !== 'object') return def;
        obj = obj[path[i]];
    }

    if(obj === undefined) return def;
    return obj;
}

//////////////////////////
//         TEST         //
//////////////////////////

var arr = [true, {'sp ace': true}, true]

var obj = {
  'sp ace': true,
  arr: arr,
  nested: {'dotted.str.ing': true},
  arr3: arr
}

shouldThrow(`path(obj, "arr.0")`);
shouldBeDefined(`path(obj, "arr[0]")`);
shouldBeEqualToNumber(`path(obj, "arr.length")`, 3);
shouldBeTrue(`path(obj, "sp ace")`);
shouldBeEqualToString(`path(obj, "none.existed.prop", "fallback")`, "fallback");
shouldBeTrue(`path(obj, "nested['dotted.str.ing'])`);
<script src="https://cdn.rawgit.com/coderek/e7b30bac7634a50ad8fd/raw/174b6634c8f57aa8aac0716c5b7b2a7098e03584/js-test.js"></script>
 39
Author: TheZver,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-27 10:47:43

Używając eval:

var part1name = eval("someObject.part1.name");

Wrap aby zwrócić undefined w przypadku błędu

function path(obj, path) {
    try {
        return eval("obj." + path);
    } catch(e) {
        return undefined;
    }
}

Http://jsfiddle.net/shanimal/b3xTw/

używaj zdrowego rozsądku i ostrożności podczas władania mocą evala. Jest trochę jak miecz świetlny, jeśli go włączysz, jest 90% szans, że odetniesz kończynę. To nie dla wszystkich.

 26
Author: Shanimal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-24 06:55:46

Możesz uzyskać wartość elementu Deep object z notacją kropkową bez żadnej zewnętrznej biblioteki JavaScript za pomocą prostej następującej sztuczki:

new Function('_', 'return _.' + path)(obj);

W Twoim przypadku aby uzyskać wartość part1.name z someObject wystarczy wykonać:

new Function('_', 'return _.part1.name')(someObject);

Oto proste demo skrzypka: https://jsfiddle.net/harishanchu/oq5esowf/

 18
Author: Harish Anchu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-24 11:43:02

To prawdopodobnie nigdy nie ujrzy światła dziennego... ale i tak tu jest.

  1. Zamień składnię [] na .
  2. podziel na . znak
  3. Usuń puste ciągi
  4. znajdź ścieżkę (inaczej undefined)

(aby znaleźć ścieżkę do obiektu, użyj tego pathTo rozwiązanie.)

// "one liner" (ES6)

const deep_value = (obj, path) => 
path
    .replace(/\[|\]\.?/g, '.')
    .split('.')
    .filter(s => s)
    .reduce((acc, val) => acc && acc[val], obj);
    
// ... and that's it.

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'
        }
        // ...
    ],
    'pa[rt3' : [
        {
            'name': 'Part 3A',
            'size': '10',
            'qty' : '20'
        }
        // ...
    ]
};

console.log(deep_value(someObject, "part1.name"));               // Part 1
console.log(deep_value(someObject, "part2.qty"));                // 60
console.log(deep_value(someObject, "part3[0].name"));            // Part 3A
console.log(deep_value(someObject, "part3[0].....name"));        // Part 3A - invalid blank paths removed
console.log(deep_value(someObject, "pa[rt3[0].name"));           // undefined - name does not support square brackets
 16
Author: Nick Grealy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-25 23:37:00

Jest to jeden liniowiec z lodash.

const deep = { l1: { l2: { l3: "Hello" } } };
const prop = "l1.l2.l3";
const val = _.reduce(prop.split('.'), function(result, value) { return result ? result[value] : undefined; }, deep);
// val === "Hello"
Albo nawet lepiej...
const val = _.get(deep, prop);

Lub wersja ES6 z redukcją...

const val = prop.split('.').reduce((r, val) => { return r ? r[val] : undefined; }, deep);

Plunkr

 14
Author: James,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-18 00:50:51

Myślę, że prosisz o to:

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

Możesz o to pytać:

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

Oba będą działać


A może prosisz o to

var partName = "part1";
var nameStr = "name";

var part1name = someObject[partName][nameStr];

W końcu możesz o to prosić

var partName = "part1.name";

var partBits = partName.split(".");

var part1name = someObject[partBits[0]][partBits[1]];
 8
Author: Hogan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-27 20:46:26

Tutaj oferuję więcej sposobów, które pod wieloma względami wydają się szybsze:

Opcja 1: Split string on . lub [Lub ] lub ' lub ", odwróć go, Pomiń puste elementy.

function getValue(path, origin) {
    if (origin === void 0 || origin === null) origin = self ? self : this;
    if (typeof path !== 'string') path = '' + path;
    var parts = path.split(/\[|\]|\.|'|"/g).reverse(), name; // (why reverse? because it's usually faster to pop off the end of an array)
    while (parts.length) { name=parts.pop(); if (name) origin=origin[name]; }
    return origin;
}

Opcja 2 (najszybsza ze wszystkich, z wyjątkiem eval): Skanowanie znaków niskiego poziomu(bez regex/split / etc, tylko Szybkie skanowanie znaków). uwaga: ten nie obsługuje cudzysłowów dla indeksów.

function getValue(path, origin) {
    if (origin === void 0 || origin === null) origin = self ? self : this;
    if (typeof path !== 'string') path = '' + path;
    var c = '', pc, i = 0, n = path.length, name = '';
    if (n) while (i<=n) ((c = path[i++]) == '.' || c == '[' || c == ']' || c == void 0) ? (name?(origin = origin[name], name = ''):(pc=='.'||pc=='['||pc==']'&&c==']'?i=n+2:void 0),pc=c) : name += c;
    if (i==n+2) throw "Invalid path: "+path;
    return origin;
} // (around 1,000,000+/- ops/sec)

Opcja 3: (nowy : opcja 2 rozszerzona o obsługę cytatów - nieco wolniejsza, ale wciąż szybko)

function getValue(path, origin) {
    if (origin === void 0 || origin === null) origin = self ? self : this;
    if (typeof path !== 'string') path = '' + path;
    var c, pc, i = 0, n = path.length, name = '', q;
    while (i<=n)
        ((c = path[i++]) == '.' || c == '[' || c == ']' || c == "'" || c == '"' || c == void 0) ? (c==q&&path[i]==']'?q='':q?name+=c:name?(origin?origin=origin[name]:i=n+2,name='') : (pc=='['&&(c=='"'||c=="'")?q=c:pc=='.'||pc=='['||pc==']'&&c==']'||pc=='"'||pc=="'"?i=n+2:void 0), pc=c) : name += c;
    if (i==n+2 || name) throw "Invalid path: "+path;
    return origin;
}

JSPerf: http://jsperf.com/ways-to-dereference-a-delimited-property-string/3

"eval(...) "jest jednak nadal królem (czyli pod względem wydajności). Jeśli masz ścieżki właściwości bezpośrednio pod kontrolą, nie powinno być żadnych problemów z używaniem 'eval' (szczególnie jeśli wymagana jest prędkość). Jeśli ciągnięcie ścieżek właściwości " over the wire "(on the line!? lol :P), to tak, użyj czegoś innego, aby być bezpiecznym. Tylko idiota powiedziałby, żeby nigdy nie używać "eval" w wszystkie, ponieważ istnieją są dobre powody kiedy go używać. Ponadto, " jest on używany w Parserze JSON Douga Crockforda."Jeśli wejście jest bezpieczne, to żadnych problemów. Użyj odpowiedniego narzędzia do właściwej pracy, to wszystko.

 7
Author: James Wilkins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:10

Na wszelki wypadek, ktoś odwiedza to pytanie w 2017 lub później i szuka łatwego do zapamiętania sposobu, oto rozbudowany post na blogu o dostępie do zagnieżdżonych obiektów w JavaScript bez bycia oszukanym przez

nie można odczytać właściwości 'foo' undefined error

Dostęp Do Zagnieżdżonych Obiektów Za Pomocą Array Reduce

Weźmy przykładową strukturę

const user = {
    id: 101,
    email: '[email protected]',
    personalInfo: {
        name: 'Jack',
        address: [{
            line1: 'westwish st',
            line2: 'washmasher',
            city: 'wallas',
            state: 'WX'
        }]
    }
}

Aby mieć dostęp do zagnieżdżonych tablic, możesz napisać własną tablicę util.

const getNestedObject = (nestedObj, pathArr) => {
    return pathArr.reduce((obj, key) =>
        (obj && obj[key] !== 'undefined') ? obj[key] : undefined, nestedObj);
}

// pass in your object structure as array elements
const name = getNestedObject(user, ['personalInfo', 'name']);

// to access nested array, just pass in array index as an element the path array.
const city = getNestedObject(user, ['personalInfo', 'address', 0, 'city']);
// this will return the city from the first address item.

Istnieje również doskonały Typ obsługi minimalnej biblioteki typy , który robi to wszystko za Ciebie.

Z typami, Twój kod będzie wyglądał tak

const city = t(user, 'personalInfo.address[0].city').safeObject;

Zastrzeżenie: jestem autorem tego pakietu.

 6
Author: Dinesh Pandiyan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-08 13:01:53

AngularJS

Podejście Speigga jest bardzo schludne i czyste, chociaż znalazłem tę odpowiedź podczas wyszukiwania rozwiązania dostępu do Właściwości AngularJS $scope za pomocą ścieżki łańcuchowej i z niewielką modyfikacją robi to zadanie:

$scope.resolve = function( path, obj ) {
    return path.split('.').reduce( function( prev, curr ) {
        return prev[curr];
    }, obj || this );
}

Po prostu umieść tę funkcję w kontrolerze root i użyj jej dowolnego zakresu podrzędnego w ten sposób:

$scope.resolve( 'path.to.any.object.in.scope')
 6
Author: nesinervink,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Nie znalazłem jeszcze pakietu do wykonywania wszystkich operacji ze ścieżką łańcuchową, więc skończyło się na napisaniu własnego szybkiego pakietu, który obsługuje operacje insert (), get() (z domyślnym zwrotem), set() I remove ().

Możesz używać notacji kropkowej, nawiasów, indeksów liczbowych, właściwości liczb ciągów oraz kluczy ze znakami innymi niż słowa. Proste użytkowanie poniżej:

> var jsocrud = require('jsocrud');

...

// Get (Read) ---
> var obj = {
>     foo: [
>         {
>             'key w/ non-word chars': 'bar'
>         }
>     ]
> };
undefined

> jsocrud.get(obj, '.foo[0]["key w/ non-word chars"]');
'bar'

Https://www.npmjs.com/package/jsocrud

Https://github.com/vertical-knowledge/jsocrud

 3
Author: Kyle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-25 01:32:44
/**
 * Access a deep value inside a object 
 * Works by passing a path like "foo.bar", also works with nested arrays like "foo[0][1].baz"
 * @author Victor B. https://gist.github.com/victornpb/4c7882c1b9d36292308e
 * Unit tests: http://jsfiddle.net/Victornpb/0u1qygrh/
 */
function getDeepVal(obj, path) {
    if (typeof obj === "undefined" || obj === null) return;
    path = path.split(/[\.\[\]\"\']{1,2}/);
    for (var i = 0, l = path.length; i < l; i++) {
        if (path[i] === "") continue;
        obj = obj[path[i]];
        if (typeof obj === "undefined" || obj === null) return;
    }
    return obj;
}

Współpracuje z

getDeepVal(obj,'foo.bar')
getDeepVal(obj,'foo.1.bar')
getDeepVal(obj,'foo[0].baz')
getDeepVal(obj,'foo[1][2]')
getDeepVal(obj,"foo['bar'].baz")
getDeepVal(obj,"foo['bar']['baz']")
getDeepVal(obj,"foo.bar.0.baz[1]['2']['w'].aaa[\"f\"].bb")
 3
Author: Vitim.us,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-29 19:51:35

Prosta funkcja, pozwalająca na ciąg znaków lub ścieżkę tablicy.

function get(obj, path) {
  if(typeof path === 'string') path = path.split('.');

  if(path.length === 0) return obj;
  return get(obj[path[0]], path.slice(1));
}

const obj = {a: {b: {c: 'foo'}}};

console.log(get(obj, 'a.b.c')); //foo

Lub

console.log(get(obj, ['a', 'b', 'c'])); //foo
 3
Author: Ben,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-26 14:42:36

Istnieje npm moduł do tego: https://github.com/erictrinh/safe-access

Przykładowe użycie:

var access = require('safe-access');
access(very, 'nested.property.and.array[0]');
 2
Author: caleb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-13 18:56:11

Chociaż redukcja jest dobra, to dziwi mnie, że nikt nie używał forEach:

function valueForKeyPath(obj, path){
        const keys = path.split('.');
        keys.forEach((key)=> obj = obj[key]);
        return obj;
    };

Test

 2
Author: Flavien Volken,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-15 14:03:14

Rozwijam sklep internetowy z Reactem. Próbowałem zmienić wartości w skopiowanym obiekcie stanu, aby zaktualizować stan ORYGINALNY z nim przy wysyłaniu. Powyższe przykłady nie zadziałały dla mnie, ponieważ większość z nich mutuje strukturę kopiowanego obiektu. Znalazłem działający przykład funkcji dostępu i zmiany wartości głęboko zagnieżdżonych właściwości obiektu: https://lowrey.me/create-an-object-by-path-in-javascript-2 / Oto jest:

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;
};
 2
Author: Dm Mh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-11 10:09:21

Niedawno miałem to samo pytanie i z powodzeniem użyłem https://npmjs.org/package/tea-properties który również set zagnieżdżony obiekt / tablice:

Get:

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

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

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

Zestaw:

var o = {};

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

assert(o.prop.arr[0].foo, 'bar'); // true
 1
Author: abernier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-04 00:41:22

Zainspirowany odpowiedzią @ webjay: https://stackoverflow.com/a/46008856/4110122

Zrobiłem tę funkcję, którą można użyć do Get / Set/ Unset dowolnej wartości w obiekcie

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

        let level = 0;
        var Return_Value;
        Path.reduce((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;
    }
}

Aby go użyć:

 // Set
 Object_Manager(Obj,[Level1,Level2,Level3],New_Value, 'Set');

 // Get
 Object_Manager(Obj,[Level1,Level2,Level3],'', 'Get');

 // Unset
 Object_Manager(Obj,[Level1,Level2,Level3],'', 'Unset');
 1
Author: Mohamad Hamouday,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-29 08:15:51

Możesz użyć ramda biblioteki.

Uczenie się ramda pomaga również w łatwej pracy z obiektami niezmiennymi.


var obj = {
  a:{
    b: {
      c:[100,101,{
        d: 1000
      }]
    }
  }
};


var lens = R.lensPath('a.b.c.2.d'.split('.'));
var result = R.view(lens, obj);


Https://codepen.io/ghominejad/pen/BayJZOQ

 1
Author: Ghominejad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-06 09:34:46

Na podstawie odpowiedzi Alnitaka .

Owinąłem polyfill w kontrolę i zmniejszyłem funkcję do pojedynczej redukcji łańcuchowej.

if (Object.byPath === undefined) {
  Object.byPath = (obj, path) => path
    .replace(/\[(\w+)\]/g, '.$1')
    .replace(/^\./, '')
    .split(/\./g)
    .reduce((ref, key) => key in ref ? ref[key] : ref, obj)
}

const data = {
  foo: {
    bar: [{
      baz: 1
    }]
  }
}

console.log(Object.byPath(data, 'foo.bar[0].baz'))
 1
Author: Mr. Polywhirl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-08 15:20:36

Jeśli potrzebujesz rozwiązania, które poprawnie wykrywa i raportuje szczegóły każdego problemu z parsowaniem ścieżek, napisałem własne rozwiązanie do tej biblioteki Path-value.

const {resolveValue} = require('path-value');

resolveValue(someObject, 'part1.name'); //=> Part 1
resolveValue(someObject, 'part2.qty'); //=> 50
resolveValue(someObject, 'part3.0.name'); //=> Part 3A

Zauważ, że dla indeksów używamy .0, a nie [0], ponieważ parsowanie tego ostatniego dodaje karę wydajności, podczas gdy .0 działa bezpośrednio w JavaScript, a tym samym jest bardzo szybkie.

Istnieje jednak również wsparcie dla pełnej składni JavaScript ES5. To po prostu musi być tokenizowane:

const {resolveValue, tokenizePath} = require('path-value');

const path = tokenizePath('part3[0].name');
//=> ['part3', '0', 'name']

resolveValue(someObject, path); //=> Part 3A
 1
Author: vitaly-t,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-30 18:38:17

Jeśli potrzebujesz uzyskać dostęp do innego zagnieżdżonego klucza bez znajomości go w czasie kodowania (adresowanie go będzie banalne), możesz użyć accessora notacji tablicy:

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

Są równoważne do notacji Dot accessor i mogą się różnić w czasie wykonywania, na przykład:

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

var part1name = someObject[part][property];

Jest równoważne

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

Lub

var part1name = someObject.part1.name;
Mam nadzieję, że to odpowiedź na twoje pytanie...

EDIT

Nie użyję ciągu do mantain pewnego rodzaju XPath zapytanie aby uzyskać dostęp do wartość obiektu. Ponieważ musisz wywołać funkcję, aby przetworzyć zapytanie i pobrać wartość, podążałbym inną ścieżką (nie:

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);

Lub, jeśli jesteś niespokojny z zastosuj metodę

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);

Funkcje są krótsze, jaśniejsze, interpreter sprawdza je za ciebie pod kątem błędów składniowych i tak dalej.

Przy okazji, czuję, że proste zadanie wykonane we właściwym czasie będzie wystarczające...
 0
Author: Eineki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-27 11:35:18

Co z tym rozwiązaniem:

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

A ten, za zdobycie:

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

Prawdopodobnie niektórzy uznają je za niebezpieczne, ale muszą być wtedy znacznie szybsze, analizując ciąg znaków.

 0
Author: Jonan Georgiev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-04 19:54:04

Rozwiązania tutaj służą tylko do uzyskiwania dostępu do głęboko zagnieżdżonych kluczy. Potrzebowałem go do uzyskiwania dostępu, dodawania, modyfikowania i usuwania kluczy. Oto co wymyśliłem:

var deepAccessObject = function(object, path_to_key, type_of_function, value){
    switch(type_of_function){
        //Add key/modify key
        case 0: 
            if(path_to_key.length === 1){
                if(value)
                    object[path_to_key[0]] = value;
                return object[path_to_key[0]];
            }else{
                if(object[path_to_key[0]])
                    return deepAccessObject(object[path_to_key[0]], path_to_key.slice(1), type_of_function, value);
                else
                    object[path_to_key[0]] = {};
            }
            break;
        //delete key
        case 1:
            if(path_to_key.length === 1){
                delete object[path_to_key[0]];
                return true;
            }else{
                if(object[path_to_key[0]])
                    return deepAccessObject(object[path_to_key[0]], path_to_key.slice(1), type_of_function, value);
                else
                    return false;
            }
            break;
        default:
            console.log("Wrong type of function");
    }
};
  • path_to_key: ścieżka w tablicy. Możesz go zastąpić przez string_path.split(".").
  • type_of_function: 0 dla dostępu (nie przekazuje żadnej wartości do value), 0 dla dodawania i modyfikowania. 1 do usunięcia.
 0
Author: ayushgp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-23 09:45:46

Budowanie z odpowiedzi Alnitaka:

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;
  };

}

To pozwala również ustawić wartość!

Stworzyłem pakiet npmi github z tym również

 0
Author: Tamb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-15 21:40:23

Zamiast ciągu można użyć tablicy adresującej zagnieżdżone obiekty i tablice np.: ["my_field", "another_field", 0, "last_field", 10]

Oto przykład, który zmieniłby pole na podstawie tej reprezentacji tablicy. Używam czegoś takiego w reaccie.js dla kontrolowanych pól wejściowych, które zmieniają stan zagnieżdżonych struktur.

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
Author: Jodo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-25 08:12:18