Динамічний доступ до властивості об'єкта за допомогою змінної


721

Я намагаюся отримати доступ до властивості об’єкта за допомогою динамічного імені. Чи можливо це?

const something = { bar: "Foobar!" };
const foo = 'bar';
something.foo; // The idea is to access something.bar, getting "Foobar!"

Відповіді:


958

Є два способи доступу до властивостей об'єкта:

  • Позначення крапок: something.bar
  • Позначення в дужці: something['bar']

Значення між дужками може бути будь-яким виразом. Тому, якщо ім'я властивості зберігається у змінній, вам потрібно використовувати позначення дужок:

var foo = 'bar';
something[foo];
// both x = something[foo] and something[foo] = x work as expected

34
обережно з цим: компілятори javascript тут
помиляться,

6
Ще трохи інформації про те, чому це можливо: JS-об'єкти - це асоціативні масиви, ось чому. Додаткова література: quirksmode.org/js/associative.html stackoverflow.com/questions/14031368 / ...
Sudhanshu Мішра

@dotnetguy Ні, вони не є. Масиви - це об'єкти, які успадковують від простого прототипу JS-об'єкта, і тому ви можете додати властивості ходу, як і будь-який звичайний об'єкт. "Асоціативна" поведінка більше нагадує об'єкт, ніж масив. Ви не можете повторити "асоціативну" версію простим індексом, щоб вона не відображала поведінку, що нагадує масив. Ви можете визначити свій "асоціативний" масив як {} або [] і трактувати його однаково в будь-якому випадку, що стосується випадкового доступу до властивостей.
Перемогла Wombat

3
@VanquishedWombat Не впевнений, до чого відноситься ваше заперечення? Я не сказав, що об'єкти JS - це масиви?
Sudhanshu Mishra

1
Ця відповідь є занадто
переголосованою

104

Це моє рішення:

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

Приклади використання:

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'})

Відмінна відповідь, дивіться також: stackoverflow.com/questions/37510640/…
Юліанський лицар

2
Ви надихнули мене на створення вдосконаленої версії, яка дозволяє позначити
Джуліан Найт

Я люблю це рішення. Однак я намагаюся змінити значення в оригінальному об'єкті, здається, що ваша функція повертає субкопію об'єкта. Чи можна змінити його так, що зміна повернутого об'єкта змінює оригінал?
Eagle1

40

На JavaScript ми можемо отримати доступ:

  • крапка - foo.bar
  • квадратні дужки - foo[someVar]абоfoo["string"]

Але лише другий випадок дозволяє динамічно отримувати доступ до властивостей:

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

4
Я дивлюся на 2000 рядків операторів if, тому що попередній розробник не використовував квадратні дужки, а статично доступний властивостям об'єкта за допомогою крапкових позначень. Це додаток для процесу затвердження, який має 7 різних схвалив, і кроки є однаковими. / рип
Чад

26

Далі наводиться приклад ES6, як можна отримати доступ до властивості об’єкта, використовуючи ім’я властивості, яке було динамічно генеровано шляхом об'єднання двох рядків.

var suffix = " name";

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

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

Це називається обчисленими іменами властивостей


16

Цього можна досягти досить кількома різними способами.

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

foo.bar;
foo['bar'];

Позначення в дужках є особливо потужним, оскільки дозволяє вам отримати доступ до властивості на основі змінної:

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

let prop = 'bar';

foo[prop];

Це можна поширити і на циклічне обслуговування над усіма властивостями об'єкта. Це може здатися зайвим через новіші конструкції JavaScript, такі як ... of ..., але допомагає проілюструвати випадок використання:

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

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

Як точки, так і позначення дужок також працюють, як очікувалося, для вкладених об'єктів:

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

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

Руйнування об'єкта

Ми також могли б розглянути деструктурування об'єктів як засіб доступу до властивості в об'єкті, але так:

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'

11

Ви можете зробити це так, використовуючи Lodash get

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

Існує багато ситуацій, таких як глибокі вкладені об'єкти пошуку, де це єдиний варіант.
Джонатан Кемпф

8

ОНОВЛЕНО

Я взяв до уваги коментарі нижче і погодився. Евалу слід уникати.

Доступ до властивостей кореня в об'єкті легко досягти obj[variable], але отримання вкладених матеріалів ускладнює. Не писати вже написаний код я пропоную використовувати lodash.get.

Приклад

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

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

Lodash get можна використовувати різними способами, ось посилання на документацію lodash.get


4
Краще уникати використання, evalколи це можливо. stackoverflow.com/questions/86513/…
Лука

8
Використання evalдля чогось тривіального в якості доступу до властивостей є простим надмірним і навряд чи доцільним при будь-яких обставинах. У чому «біда»? obj['nested']['test']працює дуже добре і не вимагає від вас вставляти код у рядки.
Kyll

3
eval втричі повільніше або більше, я б не рекомендував цього новачкам, оскільки це може навчити їх шкідливим звичкам. Я використовую obj['nested']['value']- пам’ятайте, діти, евал - це зло!
jaggedsoft

1
@Luke Зараз він єдиний хоче принести Лодаша _.getдо столу. Я вважаю, що ця відповідь заслуговує на теперішнє оновлення, а не низових. Це може бути зайвим, але добре знати, що воно існує.
Еміль Бержерон

1
Дякуємо, що представили лодаш за це. Сюди я завітав google, шукаючи метод встановити значення глибоко в об’єкті, і використав їх метод _.set (який ідентичний вище, але з додатковою аргументацією для встановлення значення).
TPHughes

5

Кожного разу, коли вам потрібно динамічно отримувати доступ до ресурсу, ви повинні використовувати квадратну дужку для доступу не "". Синтаксис оператора
: object [власність}

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


4

Я натрапив на випадок, коли я вважав, що хочу передати "адресу" властивості об'єкта як даних іншій функції та заповнити об'єкт (за допомогою AJAX), зробити пошук з адресного масиву та відобразити в цій іншій функції. Я не міг використати позначення крапок, не роблячи строкову акробатику, тому я подумав, що масив може бути замість цього пройти. Я все-таки робив щось інше в будь-якому випадку, але, здавалося, пов’язаний з цією посадою.

Ось зразок об’єкта мовного файлу, як той, з якого я хотів дані:

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

Я хотів мати можливість передавати масив, такий як: ["audioPlayer", "управління", "стоп"] для доступу до мовного тексту, "stop" у цьому випадку.

Я створив цю маленьку функцію, яка шукає параметр "найменш конкретного" (першого) адреси і переназначає повернений об'єкт собі. Тоді він готовий шукати наступний найбільш конкретний параметр адреси, якщо такий існує.

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

використання:

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

/* returns 'use controls to start and stop audio.' */
console.log(getText(["audioPlayer", "heading"], locs)); 

2

Це стає цікавим, коли вам доведеться передавати параметри і цій функції.

Код 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

1

ES5 // Перевірка глибоко вкладених змінних

Цей простий фрагмент коду може перевірити наявність глибоко вкладених змінних / значень без необхідності перевіряти кожну змінну попутно ...

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

Вих. - глибоко вкладений масив об'єктів:

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

Замість :

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

Зараз ми можемо:

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

Ура!


1
Якщо рішення - використовувати eval, ви просто створили мільйон інших проблем.
Родріго Лейте

@RodrigoLeite добре, так що не буде проблемою дати хоча б один ...


1
@RodrigoLeite Я прочитав це і оновив рішення, щоб використовувати його Functionзамість

0

Я поставив запитання, яке колись повторювалося на цю тему, і після надмірних досліджень і, побачивши, що багато інформації не вистачає, яка повинна бути тут, я відчуваю, що мені є щось цінне додати до цієї старшої публікації.

  • По-перше, я хочу зазначити, що існує кілька способів отримати значення властивості та зберегти його в динамічній змінній. Першим найпопулярнішим та найпростішим способом IMHO був би:
let properyValue = element.style['enter-a-property'];

проте я рідко йду цим маршрутом, оскільки він не працює на значення властивостей, призначені за допомогою таблиць стилів. Щоб навести вам приклад, я продемонструю за допомогою трохи псевдокоду.

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

Використовуючи приклад коду вище; якщо властивість ширини елемента div, яка зберігалась у змінній 'elem', була викладена у таблиці стилів CSS, а не стилізована всередині її тегу HTML, ви, без сумніву, збираєтесь отримати повернене значення невизначеного, що зберігається всередині змінної cssProp. Невизначене значення виникає тому, що для того, щоб отримати правильне значення, код, записаний всередині таблиці стилів CSS, повинен бути обчислений для того, щоб отримати значення, отже; ви повинні використовувати метод, який обчислить значення властивості, значення якого лежить в таблиці стилів.

  • Відтепер метод getComputedStyle ()!
function getCssProp(){
  let ele = document.getElementById("test");
  let cssProp = window.getComputedStyle(ele,null).getPropertyValue("width");
}

W3Schools getComputedValue Doc Це хороший приклад, і ви можете грати з ним, однак, це посилання Mozilla CSS getComputedValue doc детально розповідає про функцію getComputedValue, і її повинен читати будь-який прагне розробник, який не зовсім зрозумів з цього приводу.

  • Як бічна примітка, метод getComputedValue отримує лише, він не встановлюється. Це, очевидно, є головним недоліком, однак є метод, який отримує з таблиць стилів CSS, а також встановлює значення, хоча це не стандартний Javascript. Метод JQuery ...
$(selector).css(property,value)

... дійсно отримує, і встановлює. Це те, що я використовую, єдиним недоліком є ​​те, що ти познайомишся з JQuery, але це, чесно кажучи, одна з дуже багатьох вагомих причин того, що кожен розробник Javascript повинен вивчити JQuery, він просто робить життя легким і пропонує такі методи, як цей, який недоступний зі стандартним Javascript. Сподіваюся, це комусь допомагає !!!


0

Для тих, хто хоче встановити значення вкладеної змінної, ось як це зробити:

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

Документація: https://lodash.com/docs/4.17.15#set

Також документація, якщо ви хочете отримати значення: https://lodash.com/docs/4.17.15#get



-4
const something = { bar: "Foobar!" };
const foo = 'bar';

something[\`${foo}\`];

7
Чому на землі ти це зробив би? Ви fooвже є рядком, тож `${foo}`точно так само, як foo. (Крім того, ваш код, здається, має кілька додаткових нахилів, які там не належать. Але це все одно буде безглуздо, навіть якщо ви виправите цю синтаксичну помилку.)
Ilmari Karonen,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.