(V8 developer here.)
Short answer: "same" != "similar".
From the function's perspective they all have the same shape { foo: number } + *
No, that's very much not what "the same shape" means. "The same shape" doesn't mean "they all have a foo
property somewhere". "The same shape" means, for example, "they each have exactly three properties foo
, bar
, baz
, in that order". (The actual internal definition includes more, but that's the upshot.)
Monomorphic code is fast because it can always do the same thing, for example always load the first property. Whereas when it has to decide what to do every time ("oh, this is one of the objects where foo
is the second property... oh, this is an object with a shape I've never seen before, let's see if it has a foo
property at all and where that might be..."), then all that figuring-out-what-to-do costs time.
If it helps your mental model, you can compare this with physical work. When a factory produces exactly one car model, you can build a simple and fast robot that tightens the exact same screw on every car, which it always finds in the exact same spot. Whereas in a garage that repairs arbitrary old cars, a robot that's supposed to tighten their screws first has to figure out where the screws even are in this particular car that it's looking at, and how to get to them. It doesn't help the robot that all cars are "similar" in that they each have a loose screw somewhere; what makes the robot's life hard is that each car is different.
Is such a case somehow covered by the JIT compiler?
Sure, it's more work under the hood, but it works just fine, and usually it's fast enough. Don't worry about premature optimizations when you don't have a performance problem.
how to refactor similar shaped objects to fit the "monomorphic" pattern?
Make the objects have exactly the same shape. For example, construct them all with the same constructor, and then don't add any properties afterwards. (And, of course, don't make some of the properties that the constructor adds conditional either, that would defeat the point.)
With class hierarchies, polymorphism is typically hard or impossible to avoid. See here for a related question.