They really aren't. Tacking random properties onto an array doesn't affect the array's length, they won't show up when using `forEach`, map, reduce, filter, or any of the other built in functions.
etc. This is ipso facto what an associative array is - a mapping of keys to values. The only difference between JS and Lua in this regard is that in JS, object keys are always strings, while in Lua they can be of any type except `nil`. So obj[1] is the same as obj["1"], but table[1] is distinct from table["1"]. However, that does not change the fundamental semantics of the data structure in question - `Object` is still mapping arbitrary (if type-constrained) keys to values, so it's still an associative array by definition. Back when JS didn't have a dedicated `Map` type, it was often used as such in practice, too.
I will also note that things like length and iteration can be defined in many different ways. E.g. the way Lua defines length (operator #) for tables - which are also associative arrays, of course - excludes non-numeric keys. And for-loop does not directly work over tables, so how you iterate depends on which iterator function you use - `for index, value in ipairs(table)` will also only iterate over numeric keys, while `for key, value in pairs(table)` will iterate over all of them. That, again, does not change the nature of the data structure in question.