Javascript використовує змінну як назву об’єкта


91

Я хочу використовувати значення змінної для доступу до об'єкта.

Скажімо, у мене є об’єкт з ім’ям myobject.

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

Приклад:

var objname = 'myobject';
{objname}.value = 'value';

Відповіді:


125

Глобальний:

myObject = { value: 0 };
anObjectName = "myObject";
this[anObjectName].value++;

console.log(this[anObjectName]);

Глобальний: v2

var anObjectName = "myObject";
this[anObjectName] = "myvalue"

console.log(myObject)

Місцевий: v1

(function() {
    var scope = this;

    if (scope != arguments.callee) {
        arguments.callee.call(arguments.callee);
        return false;
    }

    scope.myObject = { value: 0 };
    scope.anObjectName = "myObject";
    scope[scope.anObjectName].value++;

    console.log(scope.myObject.value);
})();

Місцевий: v2

(function() {  
    var scope = this;

    scope.myObject = { value: 0 };
    scope.anObjectName = "myObject";
    scope[scope.anObjectName].value++;

    console.log(scope.myObject.value);    
}).call({});

@Shaz - обидва вони фактично посилаються на один і той же обсяг ;-) (Припускаючи, що вони виконуються у браузері.) alert(this === window).
Шон Вієйра,

1
@PeeHaa - The Local приклад встановлює змінну на windowоб'єкті під назвою , objnameяке потім посилається через this... ви могли б замінити windowна thisу другому прикладі , і все буде працювати. :-)
Шон Вієйра,

1
@SeanVieira: Погляньте на оновлений приклад. Сподіваємось, це зараз працює правильно.
Шаз,

1
@Shaz - arguments.calleeзастарілий, але тим не менш це дуже розумна реалізація - і він не засмічує глобального масштабу. +1
Шон Вієйра,

1
Можливо, це не забруднює глобальну область, але створює об’єкт, який спільно використовується при кожному виклику функції. Ваша функція зберігається objnameяк властивість самої функції. Це може вийти з ладу для рекурсивних функцій. Не впевнений, як це можна використовувати в реальному світі.
Хуан Мендес,

27

Використовуйте квадратну дужку навколо імені змінної.

var objname = 'myobject';
{[objname]}.value = 'value';

7
Це ідеально і просто, і це має бути головною відповіддю.
Бред

5
Це видає виняток: SyntaxError: очікуваний вираз, отримано '.'. Вона не працює; чому так багато голосів?
Ловро

9

Це глобальна змінна? Якщо так, це насправді частина windowоб’єкта, тож ви можете це зробити window[objname].value.

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


8

Об’єкт існує в певному обсязі, тому ви майже завжди можете отримати доступ до змінної за допомогою цього синтаксису:

var objname = "myobject";
containing_scope_reference[objname].some_property = 'some value';

Єдине місце, де це стає складним завданням, - це коли ви перебуваєте в закритій області і хочете отримати доступ до локальної змінної верхнього рівня. Коли у вас є щось подібне:

(function(){
    var some_variable = {value: 25};
    var x = "some_variable";
    console.log(this[x], window[x]); // Doesn't work
})();

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

(function(){
    var some_variable = {value: 25};
    var x = "some_variable";
    eval(x).value = 42;
    console.log(some_variable); // Works
})();

Ваш найкращий вибір повинен мати посилання на ім'я в постійно триваючий-к-бути-там об'єкта (наприклад , thisв глобальному масштабі або приватної змінної верхнього рівня в локальній області) і поставити все ще там.

Отже:

var my_outer_variable = {};
var outer_pointer = 'my_outer_variable';
// Reach my_outer_variable with this[outer_pointer]
// or window[outer_pointer]

(function(){
    var my_inner_scope = {'my_inner_variable': {} };
    var inner_pointer = 'my_inner_variable';
    // Reach my_inner_variable by using
    // my_inner_scope[inner_pointer]
})();

7

Ви можете використовувати eval:

eval(variablename + ".value = 'value'");

Не evalвраховується evil? Якщо ні, я міг би цим скористатися. Оскільки зараз це глобально, але я хотів перевести його у функцію очищення речей.
PeeHaa

1
Лол. Якщо ім'я змінної походить від вводу користувача, переконайтеся, що ви його перевірили, щоб воно не містило жодного коду JS, який evalможна виконати.
Мідас,

1
На evalмою думку, це одне з небагатьох законних застосувань . Однак ми повинні переконатися, що змінна чиста.
Леві Моррісон,

2
Так, це насправді не проблема. Але погляньте на відповідь від Shaz. Я думаю, що це більш чисте рішення.
Мідас,

2
@PeeHaa: Якщо ви плануєте перенести його, чому б не перенести його у властивість відомого об'єкта, щоб ви могли зробити щось подібне myVar[objname].value?
JW.

6

Ви не можете це зробити загалом, за винятком області вікна, де ви можете писати window[objname].value = 'value';


4

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

По суті, він використовує глобальну змінну (приєднану до об'єкта функції)

// Here's  a version of it that is more straight forward.
function doIt() {
    doIt.objname = {};
    var someObject = "objname";
    doIt[someObject].value = "value";    
    console.log(doIt.objname);
})();

Що є по суті тим же самим, що і створення глобального для зберігання змінної, тому ви можете отримати до неї доступ як властивість. Створення глобалу для цього - це такий хак.

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

function doIt() {
  var scope = {
     MyProp: "Hello"
  };
  var name = "MyProp";
  console.log(scope[name]);
}

Див. Javascript: інтерпретувати рядок як посилання на об’єкт?


1

Якщо об'єкт знаходиться в якомусь просторі імен, тобто. Company.Module.Components.FooВи можете використовувати цю функцію:

CoffeeScript:

objByName: (name, context = window) ->
    ns = name.split "."
    func = context
    for n, i in ns
        func = func[n]
    return func

Результат Js:

objByName: function(name, context) {
  var func, i, n, ns, _i, _len;
  if (context == null) {
    context = window;
  }
  ns = name.split(".");
  func = context;
  for (i = _i = 0, _len = ns.length; _i < _len; i = ++_i) {
    n = ns[i];
    func = func[n];
  }
  return func;
}

Тоді ви можете створити новий об’єкт або зробити що завгодно. Зверніть увагу на дужки.

var o = new (objByName('Company.Module.Components.Foo'))
objByName('some.deeply.nested.object').value

Ця ідея запозичена з подібного запитання: Як виконати функцію JavaScript, коли я маю її ім’я як рядок


1
let players = [];
players[something] = {};
players[something].somethingElse = 'test';
console.log(players); 

-> [щось: {somethingElse: 'тест'}];


0

Використовуючи вікно [objname], переконайтесь, що objname є глобальними змінними. В іншому випадку колись спрацює, а іноді не вдасться. вікно [objname] .value.


0

Одне із викликів, які я мав із відповідями, полягає в тому, що він припускав, що об’єкт є одним рівнем. Наприклад,

const testObj = { testKey: 'testValue' }
const refString = 'testKey';
const refObj = testObj[refString];

працює нормально, але

const testObj = { testKey:
                  { level2Key: 'level2Value' }
                }
const refString = 'testKey.level2Key';
const refObj = testObj[refString];

не працює.

У підсумку я зробив функцію для доступу до багаторівневих об’єктів:

objVar(str) {
    let obj = this;
    const parts = str.split('.');
    for (let p of parts) {
        obj = obj[p];
    }
    return obj;
}

Тоді у другому сценарії я можу передати рядок цій функції, щоб повернути об’єкт, який я шукаю:

const testObj = { testKey:
                  { level2Key: 'level2Value' }
                }
const refString = 'testObj.testKey.level2Key';
const refObj = objVar[refString];


0

Якщо ви вже знаєте список можливих імен змінних, спробуйте створити новий об'єкт (iconObj), ім'я властивостей якого збігається з іменами об'єктів. Тут, у наведеному нижче прикладі, змінна iconLib міститиме два рядкові значення, або 'ZondIcons' або 'MaterialIcons' . propertyName - це властивість об'єкта ZondIcons або MaterialsIcon.

   const iconObj = {
    ZondIcons,
    MaterialIcons,
  }
  const objValue = iconObj[iconLib][propertyName]

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.