For consistency. Even though we initialize the output context ourselves, there might be some code introduced between json_out_init_context() and dst.value() calls that replaces some of the callbacks, and then there would be a difference.
with this consistency? I didn't see this style everywhere in Postgres? Isn't it premature optimization?
Well, one could call it premature pessimization due to dynamic call overhead.
IMO, the fact that json_out_init_context() sets the value callback to json_out_value is an implementation detail, the other parts of code should not rely on. And for the Explain output, there definitely going to be *some* code between context initialization and output callbacks: these are done in a number of different functions.
Again - it is necessary? Postgres still use modular code, not OOP code. I can understand the using of this technique, when I need a possibility to change behave. But these function are used for printing JSON, not printing any others.