fix: consider extra own-enumerable properties on arrays, not just indices - #112
fix: consider extra own-enumerable properties on arrays, not just indices#112rajanpanth wants to merge 1 commit into
Conversation
…ices Array/Arguments/TypedArray all dispatched to iterableEqual, which only compares length and indexed values -- so a non-index own-enumerable property added to an array (e.g. arr.extra = 'x') was silently ignored, contradicting this library's own documented rule that all own and inherited enumerable properties are considered. Scoped this to Array specifically, since that's the case I verified; Arguments/TypedArrays share the same dispatch branch and likely the same gap, but I haven't tested those, so left them as-is rather than guess.
|
Friendly follow-up on this PR 👋 When you have a moment, could you please take a look? I’m happy to update anything if needed. Thanks! |
|
presumably this and #111 are trying to solve the same problem. i haven't reviewed either yet as this isn't necessarily a bug, it could also just be a miss in documentation. we need to decide if our intent is to treat arrays as non-extensible objects or treat them like any other object (the latter is what would need this as a "fix"). |
|
Good point — agreed this hinges on intended array semantics, not just mechanics. My intent in this PR is the ‘arrays are still objects’ direction (so own enumerable props should participate in equality), and the tests are written with that model in mind.\n\nIf maintainers prefer arrays to be treated as index-only/non-extensible for equality, I’m happy to pivot this from a behavior fix into a docs clarification instead. |
|
It might be worth looking at the history here. I seem to recall we’ve flip-flopped on this a lot. |
|
I traced the history. Before 1.0, arrays went through The subsequent history points the other way: So my read is that the current behavior is an accidental 1.0 regression rather than an intentional index-only array contract. If you prefer to treat arrays as a documented exception instead, I can close this in favor of a docs change, but the pre-1.0 behavior and post-1.0 rule both support the current patch. |
Summary
Array(along withArguments/TypedArrays) dispatches toiterableEqual, which only compareslengthand indexed values — so a non-index own-enumerable property added to an array is silently ignored:This contradicts the library's own documented rule (README, "Rules" section): "All own and inherited enumerable properties are considered."
Changes
index.js: addedarrayExtraKeysEqual, called afteriterableEqualfor the'Array'case specifically. It collects own+inherited enumerable keys/symbols (via the existinggetEnumerableKeys/getEnumerableSymbolshelpers, matchingobjectEqual's own approach), filters out keys that are already-covered array indices (so holes/sparse-array semantics are untouched — those still go throughiterableEqualexactly as before), and compares whatever's left via the existingkeysEqual.Arrayonly, notArguments/TypedArrays — they share the same dispatch branch and likely the same gap, but I've only verified theArraycase, so I didn't want to guess at behavior for the others (e.g.arguments.lengthis enumerable, unlike array's, which needs its own look).test/index.js: one new case confirming extra properties are compared, and that plain arrays are unaffected.Testing
eql(new Array(3), new Array(3))andeql([1,,3], [1, undefined, 3])both still return their existing values) or symbol-keyed extras (distinct symbols with the same description still compare as different keys, matchingobjectEqual's existing symbol handling).eslintclean, aside from the same pre-existinglinebreak-style(Windows checkout CRLF, normalizes to LF on commit) findings present with or without this change.