Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 275
anqooqie Avatar asked Mar 07 '18 08:03

anqooqie


2 Answers

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.

like image 156
anqooqie Avatar answered Nov 18 '22 19:11

anqooqie


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

like image 37
TessavWalstijn Avatar answered Nov 18 '22 18:11

TessavWalstijn