anqooqie
anqooqie

Reputation: 435

Why is not "9007199254740991" treated as an integer index?

According to the specification, a string-valued property key whose numeric value is 2 ** 53 - 1 must be treated as an integer index. According to the specification, the [[OwnPropertyKeys]] internal method must enumerate property keys which is an integer index, in ascending numeric order. According to the specification, Reflect.ownKeys calls the [[OwnPropertyKeys]] internal method.

So, the following code should show property keys in ascending numeric order (i.e., ["9007199254740990", "9007199254740991"]) if my understanding is correct. However, all the existing implementations show property keys in ascending chronological order of property creation (i.e., ["9007199254740991", "9007199254740990"]).

console.log(Reflect.ownKeys({"9007199254740991": null, "9007199254740990": null}));

What is my mistake?

Upvotes: 6

Views: 1731

Answers (2)

anqooqie
anqooqie

Reputation: 435

The specification of the [[OwnPropertyKeys]] internal method in ECMAScript 2017 (and in 2018) did not match the real behavior of all major JavaScript engines, so in ECMAScript 2019, the specification has been fixed. See the discussion on GitHub.

Upvotes: 3

TessavWalstijn
TessavWalstijn

Reputation: 1736

9007199254740991 is the maximum safe integer in JavaScript.

var x = Number.MAX_SAFE_INTEGER + 1,
  y = Number.MAX_SAFE_INTEGER + 2,
  z = Number.MAX_SAFE_INTEGER + 3,
  i = Number.MAX_SAFE_INTEGER + 4,
  j = Number.MAX_SAFE_INTEGER + 5;

console.log("max: "+Number.MAX_SAFE_INTEGER);
// expected output: 9007199254740991
// real output:     9007199254740991

console.log("x:   "+x);
// expected output: 9007199254740992
// real output:     9007199254740992

console.log("y:   "+y);
// expected output: 9007199254740993
// real output:     9007199254740992

console.log("z:   "+z);
// expected output: 9007199254740994
// real output:     9007199254740994

console.log("i:   "+i);
// expected output: 9007199254740995
// real output:     9007199254740996

console.log("j:   "+j);
// expected output: 9007199254740996
// real output:     9007199254740996

And some acts like expected.

Read on the following:

  1. MDN web docs > Number.MAX_SAFE_INTEGER
  2. What is JavaScript's highest integer value that a number can go to without losing precision?

So what we know:

bitwise operators and shift operators operate on 32-bit ints, so in that case, the max safe integer is 231-1, or 2147483647.

What I do not know is how the Reflect.ownKeys() sorts the indexes to numeric order.
Because of the following snippet:

const objs = [
    // does not work
    {
        9007199254740991: null,
        9007199254740990: null,
    },
    // works
    {
        2147483648: null,
        // max save bitwise number
        2147483647: null,
    },
    // works
    {
        4294967295: null,
        // max save bitwise number times 2
        4294967294: null,
    },
    // does not work
    {
        5368709118: null,
        // max save bitwise number times 2.5
        5368709117: null,
    }
];

const objkeys = [],
    max = objs.length;

for (let i = 0; i < max; i++) {
    objkeys.push(Reflect.ownKeys(objs[i]))
}

for (let i = 0; i < max; i++) {
    console.log(objkeys[i][0]+" < "+objkeys[i][1]);
}

I hoped you learned something about 9007199254740991 and JavaScript

Upvotes: 1

Related Questions