Skip to content

[JS] Adopt additional modern JS patterns and ESLint rules. NFC - #28138

Open
sbc100 wants to merge 2 commits into
emscripten-core:mainfrom
sbc100:modern_js
Open

sbc100 wants to merge 2 commits into
emscripten-core:mainfrom
sbc100:modern_js

Conversation

@sbc100

@sbc100 sbc100 commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator

Follow-up to #28129 and #28139

  • Enable prefer-exponentiation-operator, prefer-object-spread, prefer-rest-params, prefer-spread, and logical-assignment-operators in eslint.config.mjs.
  • Use Object.values, direct integer indexing, or ??= in places where $hasOwn is not needed.
  • Use Map instead of plain {} objects for lookup tables in acorn-optimizer.mjs and libglfw.js.
  • Replace legacy Array.prototype.slice.call, .apply, .indexOf, Math.pow, and arr[arr.length - 1] idioms with .slice, Array.from, spread syntax, .includes, ** / Math.hypot, and .at(-1).

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request modernizes the codebase by adopting several ES6+ features and enforcing them via new ESLint rules. Key changes include replacing Math.pow with the exponentiation operator (**), utilizing Array.from and .slice() instead of Array.prototype.slice.call, adopting .at(-1) for accessing the last element of arrays, replacing indexOf checks with .includes(), and using logical assignment operators (??=, ||=). Additionally, some plain objects were refactored to use Map. Feedback on these changes highlights potential issues with the new logical assignment operators. Specifically, using ??= on objects or constructors (such as derivedClass.constructor and SDL.joystickNamePool) can bypass assignments if the property name collides with inherited prototype properties (e.g., toString or constructor). Reverting to Object.hasOwn checks is recommended in these cases. Furthermore, converting a typed array to a standard array via Array.from(arg).slice(0, 400) in src/runtime_debug.js is highly inefficient for large arrays; slicing the typed array first with .subarray(0, 400) before calling Array.from is suggested to avoid unnecessary memory copying.

Comment thread src/lib/libembind.js Resolved
Comment thread src/runtime_debug.js Resolved
Comment thread src/lib/libsdl.js Resolved
Historically, `Array.prototype.slice.call` was used in two places in our
JS runtime and library code:

1. On `TypedArray` instances (in `libglemu.js`, `libmemfs.js`, and
   `runtime_debug.js`). Before ES2015 incorporated `TypedArray` into the
   ECMAScript standard, the Khronos WebGL `TypedArray` specification
   lacked `%TypedArray%.prototype.slice()` for shallow copying as well
   as `%TypedArray%.prototype.toString()` for comma-separated formatting
   (calling `.toString()` inherited `Object.prototype.toString` and
   produced `"[object Float32Array]"`). Converting to a plain `Array`
   via `Array.prototype.slice.call` was therefore necessary both to
   clone matrices in `glPushMatrix` and to format typed arrays in debug
   logs.
2. On `arguments` objects (in `jsifier.mjs` and `libcore.js`) before
   `Array.from()` was introduced in ES2015.

`%TypedArray%.prototype.slice()`, `%TypedArray%.prototype.toString()`,
and `Array.from()` have all been supported since Chrome 45, Firefox 38,
Safari 10, and Node.js 4.0 (2015-2016), well before Emscripten's minimum
supported engine versions (Chrome 85, Firefox 79, Safari 15, Node 18.3).

In `runtime_debug.js`, calling `arg.slice(0, 400)` directly also avoids
copying the entire typed array before slicing to 400 elements, and in
`glPushMatrix` it preserves the `Float32Array` type on the matrix stack.
Follow-up to emscripten-core#28129:

- Enable `prefer-exponentiation-operator`, `prefer-object-spread`,
  `prefer-rest-params`, `prefer-spread`, and
  `logical-assignment-operators` in `eslint.config.mjs`.
- Use `Object.values`, direct integer indexing, or `??=` in places
  where `$hasOwn` is not needed.
- Use `Map` instead of plain `{}` objects for lookup tables in
  `acorn-optimizer.mjs` and `libglfw.js`.
- Replace legacy `.apply`, `.indexOf`, `Math.pow`, and
  `arr[arr.length - 1]` idioms with `.call` / spread syntax,
  `.includes`, `**` / `Math.hypot`, and `.at(-1)`.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant