Only to make it clear that this is standard behavior and not a kind of lazy developper job, here are some official spec concerning the Array object :
Assert: IsPropertyKey(P) is true.
If P is "length", then
Return ? ArraySetLength(A, Desc).
Else if P is an array index, then
Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
Assert: oldLenDesc will never be undefined or an accessor descriptor because Array objects are created with length data property that cannot be deleted or reconfigured.
Let oldLen be oldLenDesc.[[Value]].
Let index be ! ToUint32(P).
If index ≥ oldLen and oldLenDesc.[[Writable]] is false, return false.
Let succeeded be ! OrdinaryDefineOwnProperty(A, P, Desc).
If succeeded is false, return false.
If index ≥ oldLen, then
Set oldLenDesc.[[Value]] to index + 1.
Let succeeded be OrdinaryDefineOwnProperty(A, "length", oldLenDesc).
Assert: succeeded is true.
Return true.
Return OrdinaryDefineOwnProperty(A, P, Desc).
So the array will treat the key as an array index if it matches the array index definition, which is :
An integer index is a String-valued property key that is a canonical numeric String (see 7.1.16) and whose numeric value
is either +0 or a positive integer ≤ 253 - 1. An array index is an integer index whose numeric value i is in the range +0 ≤ i
< 232 - 1.
Otherwise it will treat the key as an ordinary property.
source : http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf