Make class constructors work with [[Call]] too?

# Domenic Denicola (11 years ago)

Given that all non-primitive built-ins behave this way, and that including if (!(this instanceof ConstructorName)) { return new ConstructorName(...args); } is a well-established best practice for ES5 code: can we just do this automatically for classes declared with class?

# Claude Pache (11 years ago)
  • Date() and new Date give different results;
  • It would add complexity (for the programmer) to have constructors defined the ES1-5 way and constructors defined using class behave differently;
  • Opinions differ on best practices.
# Kang-Hao (Kenny) Lu (11 years ago)

(2013/07/02 13:09), Domenic Denicola wrote:>

Given that all non-primitive built-ins behave this way, and that including if (!(this instanceof ConstructorName)) { return new ConstructorName(...args); } is a well-established best practice for ES5 code:

Are you sure? What libraries do that? Having explict 'new' seems to have to benefits of identifying places of codes where new objects are created, which could be very useful if you later want to remove these object creation sites (for better GC, etc.).

Or is this just Python-ism?

# Domenic Denicola (11 years ago)

From: Kang-Hao (Kenny) Lu [kanghaol at oupeng.com]

Are you sure? What libraries do that?

Well, jQuery's a pretty famous one.

# Rick Waldron (11 years ago)

On Fri, Jul 5, 2013 at 1:13 PM, Domenic Denicola < domenic at domenicdenicola.com> wrote:

From: Kang-Hao (Kenny) Lu [kanghaol at oupeng.com]

Are you sure? What libraries do that?

Well, jQuery's a pretty famous one.

jQuery doesn't do that specifically, but does something similar enough to produce a new instance when invoked without "new" (which is how it's always invoked).

Regardless, I support your claim. It's not that library authors use this pattern in all constructor definitions, all the time—it's a pattern used by responsible authors when creating constructors to ensure user code will just work, whether invoked with or without "new".

Back to Domenic's original post... I would also like this to be the default semantics for class, but wonder if that will bite program code that assumes (incorrectly, if it doesn't abide strict mode) these have the same invocation semantics:

class Foo {} function Foo() {}

Whereas...

class Foo {} function Foo() { "use strict"; }

Do have the same observable invocation semantics (currently), but would produce something different if class always produced an instance, with or without "new".

...But this is only a "refactoring from ES5 to ES6" hazard and may not even be an issue. What do you think?

# Domenic Denicola (11 years ago)

From: Rick Waldron [waldron.rick at gmail.com]

Regardless, I support your claim. It's not that library authors use this pattern in all constructor definitions, all the time—it's a pattern used by responsible authors when creating constructors to ensure user code will just work, whether invoked with or without "new".

Indeed. I actually first thought of it in the context of how we want the DOM to work, now that there's a push for actual constructors. I thought the DOM types should probably work like the built-in types do (viz. Object, Array, Function, and RegExp, albeit not Date as Claude points out). And if were to specify something about DOM constructors generally, we should make sure it follows ES6 class syntax.

Back to Domenic's original post... I would also like this to be the default semantics for class, but wonder if that will bite program code that assumes (incorrectly, if it doesn't abide strict mode) these have the same invocation semantics:

I see what you're saying, but I think classes already have minor tweaks (e.g. default super-invocation and the existence of super) that one more wouldn't hurt. At least, that was my logic :P

# Herby Vojčík (11 years ago)

Domenic Denicola wrote:

I see what you're saying, but I think classes already have minor tweaks (e.g. default super-invocation and the existence of super) that one more wouldn't hurt. At least, that was my logic :P

Going by this logic, one can argue for other tweaks instead - for example - I repeat myself - to fix the super vs. new disrepancy by introducing saner sematics for new Class (calling F.prorotype.constructor instead of F, thus doing (more or less, with special non-typeof-object exceptional case) F[@@create].constructor(...args) instead of F.call(F[@@create], ...args) and be aligned with super). And one can easily include [[Call]] into it by making F itself being compiled into return new F(...args) (and include the working code itself in the constructor).

P.S.: In fact, I would say, for future, the new semantics (F[@@create].constructor(...args)) should be the default for any object usable with new, since it is totally generic (no need for F.c all to work; just having [@@create] and produce thing with .constructor) and leaving the old one for legacy constructor functions.