diff --git a/changelog.d/11840-class-fresh-evaluations.md b/changelog.d/11840-class-fresh-evaluations.md new file mode 100644 index 0000000000..7dbf35e9a2 --- /dev/null +++ b/changelog.d/11840-class-fresh-evaluations.md @@ -0,0 +1,39 @@ +**A class declaration evaluated more than once now creates a fresh class on every evaluation after the first, as Node does** (#11759). + +`function f() { class K {} return K }` returned the same class on every call, so `f() === f()` was `true`, a property written to one evaluation's `prototype` showed up on the other's instances, `instanceof` answered `true` across evaluations, and every evaluation shared the same static fields. The same happened for a class declared in a module-level loop body. Classes that capture variables, have private elements, or have a computed key or a runtime `extends` value were already fresh per evaluation. + +The fix follows owner decision 64, option (c′). The first evaluation of a declaration is still the shared class, so code that runs once keeps the static class and its fast paths: bundle wrappers (esbuild `__esm`/`__commonJS` bodies, which only the runtime can see running once), functions called once, and module top level. The second and later evaluations each create a fresh class object, built from #11780's template shapes. + +- **The evaluation check.** Whether the first evaluation has happened is a fact of the class template: a module-private word per template (`@perry_class_first_eval.