最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

ecmascript 6 - JavaScript casts keys with numerical strings to Numbers... but Object.keys() doesn't - Stack Overflow

programmeradmin2浏览0评论

An external API returns a JSON result of the following form:

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

Here, the keys "1.0", "2.3", "3.6" should really be taken as strings denoting a discrete categorisation, not as values along a continuous axis. It is therefore perfectly valid for this API to return these keys as strings.

However... (you can feel it ing, aren't you?)

In the JS client, I need to iterate over these keys and here es the trouble:

  • the browser's JS engine automatically casted all these keys into Number
  • using Object.keys(myObject.data) returns... strings!
  • therefore, the following does not work at all as you can see:

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

An external API returns a JSON result of the following form:

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

Here, the keys "1.0", "2.3", "3.6" should really be taken as strings denoting a discrete categorisation, not as values along a continuous axis. It is therefore perfectly valid for this API to return these keys as strings.

However... (you can feel it ing, aren't you?)

In the JS client, I need to iterate over these keys and here es the trouble:

  • the browser's JS engine automatically casted all these keys into Number
  • using Object.keys(myObject.data) returns... strings!
  • therefore, the following does not work at all as you can see:

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

It seems that we have two conflicting things here: first, the object keys are converted into Numbers, but at the same time, Object.keys() returns Strings instead of Numbers.

Is there an appropriate way to solve this problem?

Ideally, I'd like the object's actual keys to remain strings, as they should be. Casting the values from Object.keys() into Numbers would lead to quite cumbersome workarounds as the API can (and does) return "real" strings as keys sometimes (like { "red": 'foo', "blue": 'bar' }.

Share Improve this question edited Mar 17, 2019 at 12:34 adiga 35.3k9 gold badges65 silver badges87 bronze badges asked Mar 17, 2019 at 12:26 JivanJivan 23.1k16 gold badges92 silver badges143 bronze badges 3
  • 2 use for of loop – dankobgd Commented Mar 17, 2019 at 12:31
  • 3 console.log(k, myObject.data[k]) prints out // 0 undefined 1 undefined and not "1.0" undefined. Check @CodeManiac's answer. Object.keys() returns an array. You can simply use for (let k in myObject.data){} instead – adiga Commented Mar 17, 2019 at 12:32
  • "the browser's JS engine automatically casted all these keys into Number" - um, no, what makes you think that? Object keys are always strings (or symbols), never numbers. – Bergi Commented Mar 17, 2019 at 14:29
Add a ment  | 

3 Answers 3

Reset to default 8

Your problem is for in

for in tries to access keys in array created by Object.keys(obj.data) which is actually index

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

Simply do not use 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])
}

Some explanation:

Object.keys does what it says - extracts keys from the passed in object and returns them as array (in your case that'd be: [ "1.0", "2.3", "3.6"]). So when you are trying to loop over this with for..in, you are in fact looping over that resulting array, instead of the actual object and key variable will receive an index of the corresponding item from the array (0 for "1.0", 1 for "2.3", etc). That's just how for..in works. If you would like to loop over the values of the array instead, you could use for..of as another option. Or in your case, as I've mentioned above, simply do not use Object.keys.

The problem is with the for..in loop, try for..of to solve this issue. The for..in loop will iterate over all enumerable properties of the object itself and those the object inherits from its constructor's prototype.

Whereas for..of on the other hand, is mainly interested in values of iterable objects in this case it is an array returned by the Object.keys() call.

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

Here when you are iterating through the Object.keys(myObject.data), it is considering the indices(keys of array object) of the returned array instead of the actual values of myObject.data array.

Here is the distinction with a small example:

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

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论