JavaScript преобразует ключи с числовыми строками в Numbers ..., но Object.keys () этого не делает - PullRequest
6 голосов
/ 17 марта 2019

Внешний API возвращает результат JSON в следующей форме:

{
    "data": {
        "1.0": 'foo',
        "2.3": 'bar',
        "3.6": 'baz'
    }
}

Здесь ключи "1.0", "2.3", "3.6" действительно должны восприниматься как строки, обозначающие дискретную категоризацию, , а не как значения вдоль непрерывной оси. Поэтому для этого API вполне допустимо возвращать эти ключи в виде строк.

Однако ... (Вы чувствуете, что это идет, не так ли?)

В клиенте JS мне нужно перебрать эти ключи, и вот проблема:

  • движок JS браузера автоматически преобразует все эти ключи в Number
  • с использованием Object.keys(myObject.data) возвращает ... строки!
  • поэтому следующее вообще не работает , как вы можете видеть:

let myObject = {
  "data": {
    "1.0": 'foo',
    "2.3": 'bar',
    "3.6": 'baz'
  }
}

console.log(myObject.data)
for (let k in Object.keys(myObject.data)) {
  console.log(k, myObject.data[k])
}

// {
//     1.0: 'foo',
//     2.3: 'bar',
//     3.6: 'baz
// }
// "1.0" undefined
// "2.3" undefined
// "3.6" undefined

Кажется, что у нас есть две противоречивые вещи: во-первых, ключи объектов преобразуются в числа, но в то же время Object.keys() возвращает строки вместо чисел.

Есть ли подходящий способ решить эту проблему?

В идеале, я бы хотел, чтобы фактические ключи объекта оставались строками, как и должно быть. Преобразование значений из Object.keys() в Numbers приведет к довольно громоздким обходным путям, так как API может (и делает) возвращать «реальные» строки в виде ключей иногда (например, { "red": 'foo', "blue": 'bar' }.

Ответы [ 3 ]

8 голосов
/ 17 марта 2019

Ваша проблема for in

for in пытается получить доступ к ключам в массиве, созданном Object.keys(obj.data), который фактически является индексом

let obj = {"data": {"1.0": 'foo',"2.3": 'bar',"3.6": 'baz'}}

Object.keys(obj.data).forEach(e=>{
  console.log(typeof e)
})

//You can simply drop of Object.keys 

for (let k in obj.data) {
  console.log(k, obj.data[k])
}
6 голосов
/ 17 марта 2019

Просто не используйте Object.keys:

let myObject = {
  "data": {
    "1.0": 'foo',
    "2.3": 'bar',
    "3.6": 'baz'
  }
}

console.log(myObject.data)
for (let k in myObject.data) {
  console.log(k, myObject.data[k])
}

Некоторые объяснения:

Object.keys делает то, что говорит - извлекает ключи из переданного объекта и возвращает их в виде массива ( в вашем случае это будет: [ "1.0", "2.3", "3.6"]). Поэтому, когда вы пытаетесь зациклить это с помощью for..in, вы фактически зацикливаетесь на этом результирующем массиве, вместо фактического объекта, и переменная key получит index соответствующего элемента из массив (0 для "1.0", 1 для "2.3" и т. д. ). Вот как for..in работает . Если вы хотите вместо этого перебрать значения массива, вы можете использовать for..of в качестве другой опции . Или в вашем случае, как я уже упоминал выше, просто не используйте Object.keys.

3 голосов
/ 17 марта 2019

Проблема с циклом for..in, попробуйте for..of, чтобы решить эту проблему.Цикл for..in будет перебирать все перечисляемые свойства самого объекта и те свойства, которые объект наследует от прототипа своего конструктора.

Принимая во внимание, что for..of, с другой стороны, в основном интересуется значениями итерируемых объектов, в данном случае это массив, возвращаемый вызовом Object.keys().

var myObject = {
    "data": {
        "1.0": 'foo',
        "2.3": 'bar',
        "3.6": 'baz'
    }
}
console.log(myObject.data)
for (let k of Object.keys(myObject.data)) {
    console.log(k, myObject.data[k])
}

Здесь, когда вы перебираете Object.keys(myObject.data), он учитывает индексы (ключи объекта массива) возвращенного массива вместо фактических значений myObject.dataмассив.

Вот различие с небольшим примером:

var arr = [10, 20, 30];
console.log("**for - in loop**")
//logs indices 0, 1, 2
for (i in arr){
  console.log(i);
}
console.log("**for - of loop**")
//logs values in the array 10, 20, 30
for (i of arr){
  console.log(i);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...