Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Array.prototype overwrites breaking for...in loops #6135

Closed
wants to merge 2 commits into from
Closed

Fix Array.prototype overwrites breaking for...in loops #6135

wants to merge 2 commits into from

Conversation

johannschopplich
Copy link
Contributor

@johannschopplich johannschopplich commented Jan 12, 2024

This PR …

… wishes the team a happy new year! While fixing a bug.

I'm developing a new Kirby Panel plugin, which uses a third-party JavaScript library. This library itself uses the for...in loop. The Panel itself adds two methods to the Array.prototype: sortBy and split, leading to the following error in my third-party library:

The Array.prototype contains unexpected enumerable properties: sortBy, split; thus breaking e.g. for...in iteration of Arrays.", name: "UnknownErrorException", details: "Error: The Array.prototype contains unexpected enumerable properties: sortBy, split; thus breaking e.g. for...in iteration of Arrays."

Modifying Array.prototype or any built-in prototype is generally considered a bad practice, but who cares. 🙂 Unfortunately, I can't change the third-party library and need a fix.

When you add properties to Array.prototype, they become enumerable, which means they will show up in for...in loops that iterate over arrays. This can lead to errors and bugs, especially if other parts of the codebase are not expecting these additional properties. This isn't relevant for the Panel, but Panel plugins running in the same thread.

Since the Panel has to add methods to Array.prototype and we want to avoid this error, we have another option:

  • Use Object.defineProperty: This way, they won't appear in for...in loops.

My plugin depends on the third-party library, so development is kinda blocked at the moment. If I may have a wish for the new year, it's the merge of this PR. Thanks in advance!

Fixes

Any JavaScript code that uses for...in under the hood.

Breaking changes

None.

Ready?

  • Unit tests for fixed bug/feature
  • In-code documentation (wherever needed)
  • Tests and checks all pass

For review team

Copy link
Member

@bastianallgeier bastianallgeier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's one of those decisions that we need to undo at some point. Your solution seems great to me. @distantnative what do you think?

@distantnative
Copy link
Member

Wondering if we should already use this moment t move these to normal helper functions, then use object.defineProperty as suggested to add them in a usable way to the Array object, but mark that already as deprecated.

@johannschopplich
Copy link
Contributor Author

johannschopplich commented Jan 12, 2024

I thought so as well – why not make them importable utils like all the other helpers (debounce etc.).

@distantnative distantnative changed the base branch from main to develop-minor January 12, 2024 09:11
@distantnative distantnative dismissed bastianallgeier’s stale review January 12, 2024 09:11

The base branch was changed.

@distantnative
Copy link
Member

@johannschopplich

Do you have an idea why this doesn't seem to work?

export function split() {
//...
}

Object.defineProperty(Array.prototype, "split", {
	value: split,
	enumerable: false, // This makes sure the property is not enumerable
	writable: true,
	configurable: true
});

@johannschopplich
Copy link
Contributor Author

Mmh, I guess because the this has different context. In the standalone function, it doesn't has the properties of Array.protoype. 🤔

@distantnative
Copy link
Member

Yes, the first parameter must be the array then. But somehow still didn't work for me

@distantnative
Copy link
Member

Ok I just had a stupid typo somewhere that completely threw me off.

What do you think of 48fe180?
Is Array.fromObject a similar issue?

@johannschopplich
Copy link
Contributor Author

johannschopplich commented Jan 12, 2024

48fe180 looks fine. Great solution while being backwards-compatible. 👏

Regarding Array.fromObject: Somehow it doesn't seem to throw a JS error, but I think migrating it as well would be a sustainable choice. Especially since it is rarely used.

Edit: Feel free to close this PR in favor of your commit.

@distantnative
Copy link
Member

Closing in favor of #6140

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants