Dynamicznie uzyskuj dostęp do właściwości obiektu za pomocą zmiennej

Odpowiedzi:

958

Istnieją dwa sposoby uzyskania dostępu do właściwości obiektu:

  • Notacja kropkowa: something.bar
  • Notacja w nawiasie: something['bar']

Wartość w nawiasach kwadratowych może być dowolnym wyrażeniem. Dlatego jeśli nazwa właściwości jest przechowywana w zmiennej, musisz użyć notacji nawiasowej:

var foo = 'bar';
something[foo];
// both x = something[foo] and something[foo] = x work as expected
Jan Hančič
źródło
34
ostrożnie z tym: kompilatory javascript popełniają tutaj błąd, ponieważ nie zmieniają nazw łańcuchów, ale zmieniają właściwości obiektów
chacham15,
6
Więcej informacji o tym, dlaczego jest to możliwe: obiekty JS są tablicami asocjacyjnymi, dlatego. Dalsza lektura: quirksmode.org/js/associative.html stackoverflow.com/questions/14031368/…
Sudhanshu Mishra
@dotnetguy Nie, nie są. Tablice są obiektami dziedziczącymi po prostym prototypie obiektu JS, dlatego też można dodawać właściwości go-go jak każdy zwykły obiekt. Zachowanie „asocjacyjne” jest bardziej obiektowe niż tablicowe. Nie można iterować wersji „asocjacyjnej” za pomocą prostego indeksu, aby nie wyświetlała zachowania podobnego do tablicy. Możesz zdefiniować swoją tablicę „asocjacyjną” jako {} lub [] i traktować ją tak samo w obu przypadkach, jeśli chodzi o losowy dostęp do właściwości.
Vanquished Wombat
3
@VanquishedWombat Nie wiesz, co dotyczy twój sprzeciw? Nie powiedziałem, że obiekty JS są tablicami?
Sudhanshu Mishra
1
Ta odpowiedź jest
zdecydowanie przesadzona,
104

To jest moje rozwiązanie:

function resolve(path, obj) {
    return path.split('.').reduce(function(prev, curr) {
        return prev ? prev[curr] : null
    }, obj || self)
}

Przykłady użycia:

resolve("document.body.style.width")
// or
resolve("style.width", document.body)
// or even use array indexes
// (someObject has been defined in the question)
resolve("part.0.size", someObject) 
// returns null when intermediate properties are not defined:
resolve('properties.that.do.not.exist', {hello:'world'})
abahet
źródło
Doskonała odpowiedź, zobacz także: stackoverflow.com/questions/37510640/...
Julian Knight
2
Zainspirowałeś mnie do stworzenia ulepszonej wersji, która umożliwia notację w nawiasach
Julian Knight
Uwielbiam to rozwiązanie. Jednak próbuję zmodyfikować wartości w oryginalnym obiekcie, wygląda na to, że twoja funkcja zwraca podkopę obiektu. Czy można to zmienić, aby modyfikacja zwróconego obiektu modyfikowała oryginał?
Eagle1
40

W javascript możemy uzyskać dostęp za pomocą:

  • notacja kropkowa - foo.bar
  • nawiasy kwadratowe - foo[someVar]lubfoo["string"]

Ale tylko drugi przypadek pozwala na dynamiczny dostęp do właściwości:

var foo = { pName1 : 1, pName2 : [1, {foo : bar }, 3] , ...}

var name = "pName"
var num  = 1;

foo[name + num]; // 1

// -- 

var a = 2;
var b = 1;
var c = "foo";

foo[name + a][b][c]; // bar
Sonique
źródło
4
Patrzę na 2000 wierszy instrukcji if, ponieważ poprzedni programista nie używał nawiasów kwadratowych, a właściwości obiektu były dostępne statycznie za pomocą notacji kropkowej. To jest aplikacja procesu zatwierdzania, która ma 7 różnych osób zatwierdzających, a wszystkie kroki są takie same. / rip
Czad
26

Poniżej znajduje się przykład ES6, w jaki sposób można uzyskać dostęp do właściwości obiektu za pomocą nazwy właściwości, która została dynamicznie wygenerowana przez połączenie dwóch łańcuchów.

var suffix = " name";

var person = {
    ["first" + suffix]: "Nicholas",
    ["last" + suffix]: "Zakas"
};

console.log(person["first name"]);      // "Nicholas"
console.log(person["last name"]);       // "Zakas"

Nazywa się to obliczonymi nazwami właściwości

zloctb
źródło
16

Możesz to osiągnąć na kilka różnych sposobów.

let foo = {
    bar: 'Hello World'
};

foo.bar;
foo['bar'];

Notacja w nawiasie jest szczególnie wydajna, ponieważ umożliwia dostęp do właściwości opartej na zmiennej:

let foo = {
    bar: 'Hello World'
};

let prop = 'bar';

foo[prop];

Można to rozszerzyć na zapętlenie każdej właściwości obiektu. Może to wydawać się zbędne ze względu na nowsze konstrukcje JavaScript, takie jak ... z ..., ale pomaga zilustrować przypadek użycia:

let foo = {
    bar: 'Hello World',
    baz: 'How are you doing?',
    last: 'Quite alright'
};

for (let prop in foo.getOwnPropertyNames()) {
    console.log(foo[prop]);
}

Zarówno notacja kropkowa jak i nawiasowa działają również zgodnie z oczekiwaniami dla zagnieżdżonych obiektów:

let foo = {
    bar: {
        baz: 'Hello World'
    }
};

foo.bar.baz;
foo['bar']['baz'];
foo.bar['baz'];
foo['bar'].baz;

Niszczenie obiektów

Możemy również rozważyć destrukcję obiektu jako sposób dostępu do właściwości w obiekcie, ale w następujący sposób:

let foo = {
    bar: 'Hello World',
    baz: 'How are you doing?',
    last: 'Quite alright'
};

let prop = 'last';
let { bar, baz, [prop]: customName } = foo;

// bar = 'Hello World'
// baz = 'How are you doing?'
// customName = 'Quite alright'
Gorka Hernandez
źródło
11

Możesz to zrobić za pomocą Lodash get

_.get(object, 'a[0].b.c');
Shalonteoh
źródło
Istnieje wiele sytuacji, takich jak wyszukiwanie głęboko zagnieżdżonych obiektów, gdzie jest to jedyna opcja.
Jonathan Kempf
8

AKTUALIZACJA

Uwzględniłem poniższe uwagi i zgodziłem się. Ewaluacji należy unikać.

Łatwo można uzyskać dostęp do właściwości katalogu głównego w obiekcie obj[variable], ale zagnieżdżenie komplikuje sprawę. Nie pisać już napisanego kodu, którego sugeruję użyć lodash.get.

Przykład

// Accessing root property
var rootProp = 'rootPropert';
_.get(object, rootProp, defaultValue);

// Accessing nested property
var listOfNestedProperties = [var1, var2];
_.get(object, listOfNestedProperties);

Z Lodash get można korzystać na różne sposoby, tutaj jest link do dokumentacji lodash.get

Pan Br
źródło
4
Najlepiej unikać używania, evalgdy tylko jest to możliwe. stackoverflow.com/questions/86513/…
Luke
8
Używanie evalczegoś tak trywialnego, jak dostęp do właściwości, jest zwykłym przesadą i nie jest zalecane w żadnych okolicznościach. Co to za „kłopoty”? obj['nested']['test']działa bardzo dobrze i nie wymaga osadzania kodu w łańcuchach.
Kyll
3
eval jest trzykrotnie wolniejszy lub więcej, nie poleciłbym tego początkującym, ponieważ może nauczyć ich złych nawyków. Używam obj['nested']['value']- pamiętajcie dzieci, eval jest złe!
jaggedsoft,
1
@Luke Jest teraz jedynym, który chce przynieść Lodasha _.getdo stołu. Myślę, że ta odpowiedź zasługuje teraz na głosowanie zamiast głosowania negatywnego. Może to być przesada, ale dobrze wiedzieć, że istnieje.
Emile Bergeron,
1
Dziękujemy za wprowadzenie do tego lodash. Przyszedłem tutaj przez google, szukając metody ustawiania wartości głęboko w obiekcie, i użyłem ich metody _.set (która jest identyczna z powyższą, ale z dodatkowym argumentem za ustawieniem wartości).
TPHughes,
5

Ilekroć potrzebujesz dynamicznego dostępu do właściwości, musisz użyć nawiasu kwadratowego, aby uzyskać dostęp do właściwości, a nie „.” operator
Składnia: obiekt [propery}

const something = { bar: "Foobar!" };
const foo = 'bar';
// something.foo; -- not correct way at it is expecting foo as proprty in  something={ foo: "value"};
// correct way is  something[foo]
alert( something[foo])

Rupesh Agrawal
źródło
4

Natknąłem się na przypadek, w którym myślałem, że chcę przekazać „adres” właściwości obiektu jako dane do innej funkcji i zapełnić obiekt (za pomocą AJAX), wyszukać z tablicy adresów i wyświetlić w tej innej funkcji. Nie mogłem używać notacji kropkowej bez robienia akrobatyki łańcuchowej, więc pomyślałem, że tablica może być miło przekazać Skończyło się na zrobieniu czegoś innego, ale wydawało mi się, że jestem związany z tym postem.

Oto przykład obiektu pliku językowego, takiego jak ten, z którego chciałem uzyskać dane:

const locs = {
  "audioPlayer": {
    "controls": {
      "start": "start",
      "stop": "stop"
    },
    "heading": "Use controls to start and stop audio."
  }
}

Chciałem móc przekazać tablicę, taką jak: [„audioPlayer”, „kontroluje”, „stop”], aby uzyskać dostęp do tekstu języka, w tym przypadku „stop”.

Stworzyłem tę małą funkcję, która wyszukuje „najmniej konkretny” (pierwszy) parametr adresu i ponownie przypisuje zwracany obiekt do siebie. Następnie jest gotowy wyszukać najbardziej szczegółowy parametr adresu, jeśli taki istnieje.

function getText(selectionArray, obj) {
  selectionArray.forEach(key => {
    obj = obj[key];
  });
  return obj;
}

stosowanie:

/* returns 'stop' */
console.log(getText(["audioPlayer", "controls", "stop"], locs)); 

/* returns 'use controls to start and stop audio.' */
console.log(getText(["audioPlayer", "heading"], locs)); 
Łukasz
źródło
2

To staje się interesujące, gdy musisz przekazać parametry również do tej funkcji.

Kod jsfiddle

var obj = {method:function(p1,p2,p3){console.log("method:",arguments)}}

var str = "method('p1', 'p2', 'p3');"

var match = str.match(/^\s*(\S+)\((.*)\);\s*$/);

var func = match[1]
var parameters = match[2].split(',');
for(var i = 0; i < parameters.length; ++i) {
  // clean up param begninning
    parameters[i] = parameters[i].replace(/^\s*['"]?/,'');
  // clean up param end
  parameters[i] = parameters[i].replace(/['"]?\s*$/,'');
}

obj[func](parameters); // sends parameters as array
obj[func].apply(this, parameters); // sends parameters as individual values
Jacksonkr
źródło
1

ES5 // Sprawdź głęboko zagnieżdżone zmienne

Ten prosty fragment kodu może sprawdzić głęboko zagnieżdżone istnienie zmiennych / wartości bez konieczności sprawdzania każdej zmiennej po drodze ...

var getValue = function( s, context ){
    return Function.call( context || null, 'return ' + s )();
}

Dawny. - głęboko zagnieżdżona tablica obiektów:

a = [ 
    {
      b : [
          {
             a : 1,
             b : [
                 {
                    c : 1,
                    d : 2   // we want to check for this
                 }
             ]
           }
      ]
    } 
]

Zamiast :

if(a && a[0] && a[0].b && a[0].b[0] && a[0].b[0].b && a[0].b[0].b[0] && a[0].b[0].b[0].d && a[0].b[0].b[0].d == 2 )  // true

Możemy teraz:

if( getValue('a[0].b[0].b[0].d') == 2 ) // true

Twoje zdrowie!


źródło
1
Jeśli rozwiązaniem jest użycie eval, właśnie stworzyłeś milion innych problemów.
Rodrigo Leite,
@RodrigoLeite ok, więc nie byłoby problemu dać przynajmniej jeden ...
1
@RodrigoLeite Przeczytałem to i zaktualizowałem rozwiązanie, aby Functionzamiast tego używać
0

Zadałem pytanie, które trochę powielało ten temat jakiś czas temu, a po nadmiernych badaniach i widząc wiele brakujących informacji, które powinny tu być, czuję, że mam coś cennego do dodania do tego starszego postu.

  • Po pierwsze chcę się odnieść do tego, że istnieje kilka sposobów uzyskania wartości właściwości i przechowywania jej w zmiennej dynamicznej. Pierwszym najpopularniejszym i najłatwiejszym sposobem IMHO byłoby:
let properyValue = element.style['enter-a-property'];

jednak rzadko wybieram tę trasę, ponieważ nie działa ona na wartości właściwości przypisane za pomocą arkuszy stylów. Jako przykład podam przykład z pseudo-kodem.

 let elem = document.getElementById('someDiv');
 let cssProp = elem.style['width'];

Korzystając z powyższego przykładu kodu; jeśli właściwość width elementu div, który był przechowywany w zmiennej „elem”, została stylizowana w arkuszu stylów CSS, a nie w jej znaczniku HTML, bez wątpienia otrzymasz zwrot wartości niezdefiniowanej przechowywanej w środku zmiennej cssProp. Nieokreślona wartość występuje, ponieważ aby uzyskać poprawną wartość, kod zapisany w arkuszu stylów CSS musi zostać obliczony w celu uzyskania wartości; musisz użyć metody, która obliczy wartość właściwości, której wartość leży w arkuszu stylów.

  • Odtąd metoda getComputedStyle ()!
function getCssProp(){
  let ele = document.getElementById("test");
  let cssProp = window.getComputedStyle(ele,null).getPropertyValue("width");
}

W3Schools getComputedValue Doc Daje to dobry przykład i pozwala się z nim bawić, jednak ten link Mozilla CSS getComputedValue doc mówi szczegółowo o funkcji getComputedValue i powinien być czytany przez każdego początkującego programistę, który nie jest do końca jasny na ten temat.

  • Na marginesie, metoda getComputedValue dostaje tylko, ale nie ustawia się. Jest to oczywiście poważny minus, jednak istnieje metoda, która pobiera z arkuszy stylów CSS, a także ustawia wartości, chociaż nie jest to standardowy Javascript. Metoda JQuery ...
$(selector).css(property,value)

... dostaje i ustawia. To jest to, czego używam, jedynym minusem jest to, że znasz JQuery, ale jest to szczerze jeden z wielu dobrych powodów, dla których każdy programista Javascript powinien uczyć się JQuery, ułatwia życie i oferuje metody, takie jak ta, która nie jest dostępny ze standardowym Javascript. Mam nadzieję, że to komuś pomoże !!!

Aft3rL1f3
źródło
0

Dla każdego, kto chce ustawić wartość zagnieżdżonej zmiennej, oto jak to zrobić:

const _ = require('lodash'); //import lodash module

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

_.set(object, 'a[0].b.c', 4);
console.log(object.a[0].b.c);
// => 4

Dokumentacja: https://lodash.com/docs/4.17.15#set

Ponadto dokumentacja, jeśli chcesz uzyskać wartość: https://lodash.com/docs/4.17.15#get

GavinBelson
źródło
-3

Powinieneś użyć JSON.parse, spójrz na https://www.w3schools.com/js/js_json_parse.asp

const obj = JSON.parse('{ "name":"John", "age":30, "city":"New York"}')
console.log(obj.name)
console.log(obj.age)
onmyway133
źródło
-4
const something = { bar: "Foobar!" };
const foo = 'bar';

something[\`${foo}\`];
Siergiej
źródło
7
Dlaczego, u licha, miałbyś to robić? Twój foojest już ciągiem, więc `${foo}`jest dokładnie taki sam jak foo. (Poza tym twój kod wydaje się zawierać dodatkowe ukośniki odwrotne, które tam nie należą. Ale i tak byłby bezcelowy, nawet jeśli naprawiłeś ten błąd składniowy.)
Ilmari Karonen