Як використовувати змінну для ключа в літеральному об'єкті JavaScript?


406

Чому працює наступне?

<something>.stop().animate(
    { 'top' : 10 }, 10
);

Тоді як це не працює:

var thetop = 'top';
<something>.stop().animate(
    { thetop : 10 }, 10
);

Щоб було ще зрозуміліше: на даний момент я не в змозі передати властивість CSS анімованій функції як змінної.



Відповіді:


667

{ thetop : 10 }є дійсним літеральним об'єктом. Код створить об’єкт із властивістю на ім'я, thetopяке має значення 10. Обидва наведені нижче є однаковими:

obj = { thetop : 10 };
obj = { "thetop" : 10 };

У ES5 та новіших версіях ви не можете використовувати змінну як ім'я властивості всередині об'єкта-літералу. Ваш єдиний варіант - зробити наступне:

var thetop = "top";

// create the object literal
var aniArgs = {};

// Assign the variable property name with a value of 10
aniArgs[thetop] = 10; 

// Pass the resulting object to the animate method
<something>.stop().animate(
    aniArgs, 10  
);  

ES6 визначає ComputedPropertyName як частина граматики для літералів об'єктів, що дозволяє писати код , як це:

var thetop = "top",
    obj = { [thetop]: 10 };

console.log(obj.top); // -> 10

Ви можете використовувати цей новий синтаксис в останніх версіях кожного основного браузера.


Я розумію! Дякую! Не повинен це також працювати з eval? Я маю на увазі, що це не працює на моєму прикладі на даний момент, але я тонко кажу це: ... :-)
speendo

3
@Marcel: eval()не буде працювати всередині об'єкта буквально для імен динамічних властивостей, ви просто отримаєте помилку. Мало того, але eval()насправді не слід використовувати для таких речей. Є чудова стаття про правильне та неправильне використання eval: blogs.msdn.com/ericlippert/archive/2003/11/01/53329.aspx
Енді Е

2
@AndyE розглядає можливість оновлення "останніх версій" та "поточного IE TP" на деякий конкретніший час, наприклад "Версії пізніше XXX" або "після 2014-мм" (я б змінився, але не знаю, які хороші значення було б.
Олексій Левенков

1
для ES6, чи є спосіб вимкнути властивість, якщо ключ є нульовим / невизначеним? Наприклад, {[key] : "value"}якщо клавіша була недійсною, вона дала б { null: "value"}, тоді як я хотів би, щоб результат був{}
wasabigeek

чудове рішення, але чому ви знаєте так багато, навіть прочитавши всю специфікацію, не вдалося отримати бал :(
hugemeow

126

З ECMAScript 2015 тепер ви можете це зробити безпосередньо в оголошенні об'єкта з позначеннями дужок: 

var obj = {
  [key]: value
}

Де keyможе бути будь-який вираз (наприклад, змінна), що повертає значення.

Отже, ваш код виглядатиме так:

<something>.stop().animate({
  [thetop]: 10
}, 10)

Де thetopбуде оцінено перед тим, як використовувати його як ключовий.


17

Цитата ES5, яка говорить, що вона не повинна працювати

Примітка: правила змінилися для ES6: https://stackoverflow.com/a/2274327/895245

Spec: http://www.ecma-international.org/ecma-262/5.1/#sec-11.1.5

Назва власності :

  • IdentifierName
  • StringLiteral
  • Числовий Літеральний

[...]

Виробнича PropertyName: IdentifierName оцінюється наступним чином:

  1. Поверніть значення String, що містить ту саму послідовність символів, що і ім'я IdentifierName.

Виробнича PropertyName: StringLiteral оцінюється наступним чином:

  1. Поверніть SV [значення рядка] StringLiteral.

Виробнича PropertyName: NumericLiteral оцінюється наступним чином:

  1. Нехай nbr є результатом формування значення NumericLiteral.
  2. Повернутись до ToString (nbr).

Це означає що:

  • { theTop : 10 } точно так само, як { 'theTop' : 10 }

    Оно PropertyName theTopє IdentifierName, тому воно перетворюється на 'theTop'значення рядка, яке є значенням рядка 'theTop'.

  • Неможливо записати ініціалізатори об'єктів (літерали) зі змінними клавішами.

    Єдині три варіанти: IdentifierName(розширюється на літеральний рядок) StringLiteral, і NumericLiteral(також розширюється на рядок).


3
Downvoters: Я був першим, хто цитував будь-який стандарт з цього питання. Цитата ES6 на головну відповідь була відредагована після того, як я відповів, і той стандарт ще не був прийнятий. Якщо ви випадково знаєте, чому я ще отримую голоси, поясніть, будь ласка, я просто хочу вчитися. Я можу також отримати знак тиску однолітків ...
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Я думаю, що голосування було в основному тому, що ваша відповідь не пропонує рішення і не є корисною в цьому плані. Голосування за тиск з боку однолітків :-)
Бергі

3
@Bergi дякую за те, що маєте сміливість! :-) Але я думаю, що я відповів на питання безпосередньо : Питання: "Чому працює наступне?". A: тому що ES5 так говорить. "Що з цим робити?" неявна. Ви спромоглися головного питання сказати "Неможливо" без стандартної цитати перед тим, як хтось редагував рішення ES6?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Ага, правильно. Я, як правило, цитую конкретні запитання в блок-цитаті, щоб зрозуміти, коли я відповідаю на них безпосередньо. Цитування стандарту може зробити хорошу відповідь ще кращою, але наразі ваша публікація навіть не відповідає на питання imo. Викладення того, що може зробити ключ в ES5, не означає, як вони працюють. Звичайно thetop, це IdentifierNameтак, чому це не працює ? Це питання залишається відкритим.
Бергі

1
@Bergi ще раз дякую за пояснення мені! Я оновив його, щоб зробити його більш чітким. Я цього не робив раніше, тому що я хоч і був очевидним, тому що ми можемо писати {a:1}.a, тому aявно не розширюйте значення змінної у випадку ідентифікатора. Але так, пояснення далі - це поліпшення в цій справі.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

5

Я використовував наступне, щоб додати властивість з "динамічним" ім'ям до об'єкта:

var key = 'top';
$('#myElement').animate(
   (function(o) { o[key]=10; return o;})({left: 20, width: 100}),
   10
);

key - це назва нового ресурсу.

Об'єкт властивостей, переданих до animate, буде{left: 20, width: 100, top: 10}

Це просто використання необхідних []позначень, як рекомендують інші відповіді, але з меншою кількістю рядків коду!


5

Додавання квадратної дужки навколо змінної працює добре для мене. Спробуйте це

var thetop = 'top';
<something>.stop().animate(
    { [thetop] : 10 }, 10
);

У старих версіях EcmaScript це не спрацює, але сьогодні це дуже чистий підхід.
Олівер

3

Я не зміг знайти простий приклад про відмінності між ES6 та ES5, тому зробив один. Обидва зразки коду створюють абсолютно один і той же об’єкт. Але приклад ES5 також працює у старих браузерах (як IE11), де приклад ES6 не відповідає.

ES6

var matrix = {};
var a = 'one';
var b = 'two';
var c = 'three';
var d = 'four';

matrix[a] = {[b]: {[c]: d}};

ES5

var matrix = {};
var a = 'one';
var b = 'two';
var c = 'three';
var d = 'four';

function addObj(obj, key, value) {
  obj[key] = value;
  return obj;
}

matrix[a] = addObj({}, b, addObj({}, c, d));

2

Оновлення / приклад 2020 року ...

Більш складний приклад, використовуючи дужки та літерали ... щось, що вам, можливо, доведеться робити, наприклад, з vue / axios. Загорніть буквальне слово в дужки, так

[`...`]

{
    [`filter[${query.key}]`]: query.value,  // 'filter[foo]' : 'bar'
}

1

Даний код:

var thetop = 'top';
<something>.stop().animate(
    { thetop : 10 }, 10
);

Переклад:

var thetop = 'top';
var config = { thetop : 10 }; // config.thetop = 10
<something>.stop().animate(config, 10);

Як бачимо, в { thetop : 10 }декларації не використовується змінна thetop. Натомість він створює об’єкт з назвою ключа thetop. Якщо ви хочете, щоб ключ був значенням змінної thetop, тоді вам доведеться використовувати квадратні дужки навколо thetop:

var thetop = 'top';
var config = { [thetop] : 10 }; // config.top = 10
<something>.stop().animate(config, 10);

Синтаксис квадратних дужок було введено разом з ES6. У попередніх версіях JavaScript вам слід зробити наступне:

var thetop = 'top';
var config = (
  obj = {},
  obj['' + thetop] = 10,
  obj
); // config.top = 10
<something>.stop().animate(config, 10);

1

Я не можу повірити, що це ще не було опубліковано: просто використовуйте стрілочні позначення з анонімною оцінкою!

Повністю неінвазивний, не возиться з простором імен, і він займає лише один рядок:

myNewObj = ((k,v)=>{o={};o[k]=v;return o;})(myKey,myValue);

демонстрація:

корисний у середовищах, які ще не підтримують новий {[myKey]: myValue}синтаксис, наприклад, очевидно; Я щойно перевірив це на своїй консолі веб-розробників — Firefox 72.0.1, випущеній 2020-01-08.

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


не так уже й важливо , оскільки ОП запитав це десять років тому, але заради для повноти і продемонструвати , як це точно відповідь на питання , як то кажуть, я покажу це в оригінальному контексті:

var thetop = 'top';
<something>.stop().animate(
    ((k,v)=>{o={};o[k]=v;return o;})(thetop,10), 10
);

0

Таким чином, ви також можете досягти бажаного результату

var jsonobj={};
var count=0;
$(document).on('click','#btnadd', function() {
    jsonobj[count]=new Array({ "1"  : $("#txtone").val()},{ "2"  : $("#txttwo").val()});
    count++;
    console.clear();
    console.log(jsonobj);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span>value 1</span><input id="txtone" type="text"/>
<span>value 2</span><input id="txttwo" type="text"/>
<button id="btnadd">Add</button>


0

Реалізація ES5 для призначення ключів наведена нижче:

var obj = Object.create(null),
    objArgs = (
      (objArgs = {}),
      (objArgs.someKey = {
        value: 'someValue'
      }), objArgs);

Object.defineProperties(obj, objArgs);

Я додав фрагмент, який використовував для перетворення на голий об'єкт.

var obj = {
  'key1': 'value1',
  'key2': 'value2',
  'key3': [
    'value3',
    'value4',
  ],
  'key4': {
    'key5': 'value5'
  }
}

var bareObj = function(obj) {

  var objArgs,
    bareObj = Object.create(null);

  Object.entries(obj).forEach(function([key, value]) {

    var objArgs = (
      (objArgs = {}),
      (objArgs[key] = {
        value: value
      }), objArgs);

    Object.defineProperties(bareObj, objArgs);

  });

  return {
    input: obj,
    output: bareObj
  };

}(obj);

if (!Object.entries) {
  Object.entries = function(obj){
    var arr = [];
    Object.keys(obj).forEach(function(key){
      arr.push([key, obj[key]]);
    });
    return arr;
  }
}

console(bareObj);


0

Ви можете зробити наступне для ES5:

var theTop = 'top'
<something>.stop().animate(
  JSON.parse('{"' + theTop + '":' + JSON.stringify(10) + '}'), 10
)

Або витягнути до функції:

function newObj (key, value) {
  return JSON.parse('{"' + key + '":' + JSON.stringify(value) + '}')
}

var theTop = 'top'
<something>.stop().animate(
  newObj(theTop, 10), 10
)



0

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

let array1 = [{
    "description": "THURSDAY",
    "count": "1",
    "date": "2019-12-05"
},
{
    "description": "WEDNESDAY",
    "count": "0",
    "date": "2019-12-04"
}]
let res = array1.map((value, index) => {
    return { [value.description]: { count: value.count, date: value.date } }
})
console.log(res);

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