51

In ES6 we can do anonymous class:

var entity = class {
}

But we can also immediately instantiate it:

var entity = new class {
    constructor(name) { this.name = name; }
    getName() { return this.name; }
}('Foo');
console.log(entity.getName()); // Foo

What is done behind it, what advantage will it bring and what caveats will it also bring?

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Steve Fan
  • 3,019
  • 3
  • 19
  • 29
  • Why not just use an object literal? or an actual constructor function? – evolutionxbox Aug 03 '16 at 09:24
  • 1
    Personal flavor; I like C++ and Java styled object declaration. – Steve Fan Aug 03 '16 at 09:26
  • I don't think there's anything different between this and normal prototype class creation. It's just syntax difference. https://www.quora.com/Is-class-syntax-in-ECMAScript-6-just-a-syntactic-sugar-for-classical-prototypes/answer/Fionn-Kelleher-1?srid=kdJ8 – evolutionxbox Aug 03 '16 at 09:29
  • Looks like this blog entry is decent enough to be related to my question: http://jasonwyatt.co/post/866536821/anonymous-classes-with-javascript-and-self-calling – Steve Fan Aug 03 '16 at 09:30
  • 2
    ES5 has anonymous constructors too: `entity = new function(name) { this.name = name }("Foo")`. `class` is just syntactic sugar for a constructor and some extras. So when there are anonymous constructors then there are anonymous classes as well. –  Aug 03 '16 at 09:44
  • Done. Thank you for pointing it out. – Steve Fan Aug 03 '16 at 09:49
  • I see nobody asked similar question before, so I would like to stop for advice. – Steve Fan Aug 03 '16 at 10:23
  • @torazaburo: Mostly that it probably [does not do what you think it does](https://stackoverflow.com/questions/10406552/is-it-right-to-think-of-a-javascript-function-expression-that-uses-the-new-key-as-static) – Bergi Aug 03 '16 at 10:31
  • Actually the example you posted throws a `TypeError: Cannot set property name of [object Object] which has only a getter` – Bergi Aug 03 '16 at 10:32
  • Oops. Fixed it. Thanks. @Bergi – Steve Fan Aug 03 '16 at 10:38

2 Answers2

67

Immediately instantiated anonymous class — is it a bad idea?

Yes, a very bad one. Just as bad as new function() { … } was in ES5.

This writing style leads to the creation of a new constructor function and prototype object every time the expression is evaluated. If you create multiple objects with this approach, they will get none of the benefits of classes/prototypes.

If you intended this pattern to create a singleton object, you failed as well. The constructor is still created, and it is even accessible - a second instance can be easily created using new entity.constructor, defeating the whole purpose.

So don't use it ever. A simple object literal is much easier to write, read and instantiate:

var entity = {
    name: 'Foo',
    getName() { return this.name; }
};
console.log(entity.name); // Foo

Don't be fooled by other languages where the new class pattern is common, it works very different there than in JavaScript.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 5
    readers should note the quote "This writing style leads to the creation of a new constructor function and prototype object every time the expression is evaluated. If you create multiple objects with this approach, they will get none of the benefits of classes/prototypes." -- unless I misunderstood, this is a valid objection to creating an anonymous class for every object, but is not necessarily an objection to using an anonymous class to create multiple objects, in which case they would still benefit from prototypical inheritance. (Other objections may or may not exist.) – ninjagecko Feb 26 '18 at 06:01
  • 2
    @ninjagecko Yes, the objection to using `class` for "singletons" in general. It doesn't even need to be anonymous for that. – Bergi Feb 26 '18 at 09:42
  • 7
    If you use this for singletons you haven't "failed". You can create a second instance of _any_ object by simply cloning it. JavaScript is a dynamic language, with introspection, eval and a standard library that can be modified at runtime. If you are looking to lock down your code from malicious or foolish coworkers then you picked the wrong programming language for sure! – alextgordon May 07 '19 at 23:54
  • @alextgordon Objects that make use of closures can't be cloned easily, setup logic of a singleton usually can't be run twice if it's not contained in a (constructor) method. – Bergi May 08 '19 at 08:01
  • 4
    You don't provide any clear arguments against using anonymous classes. Benefits of classes/prototypes? What are they exactly that one doesn't have when uses anonymous classes? As for "creating a class every time it's evaluated," it all depends on how often that happens (how many times) during the course of a program. The downside may be negligible in some cases. But as a general rule, yes, I'd recommend to stick to ordinary classes. Unless you have a reason not to. – x-yuri Dec 10 '20 at 11:07
  • @x-yuri The benefit of classes/prototypes is that multiple instances can share the same prototype object and its methods. This doesn't happen when you create a new class per instance, making code that uses the methods hard to optimise for engines (apart from obviously not being memory-efficient). – Bergi Dec 10 '20 at 11:57
  • @Bergi The problem with duplicating the methods on every "new class ..." also applies to an object literal. Eg the "getName" method in the example. The only solution to that problem is to define a top level class and instantiate it. – Jesse Jan 02 '22 at 15:59
  • @Jesse Neither the `new class {…}` nor the `{…}` object literal are duplicated? The goal here was a singleton, not a factory function (where, indeed, `new class` is just as horrible). – Bergi Jan 02 '22 at 16:22
  • @Bergi You said "The benefit of classes/prototypes is that multiple instances can share the same prototype object and its methods." but methods on object literals are not shared either. – Jesse Jan 02 '22 at 18:06
  • @Jesse Oh, yes you're right, if one wants to create multiple objects one should move the class definition outside of the repeated code section (be it a factory function or loop or something else). I recommend the object literal for where only a single object is to be created. – Bergi Jan 02 '22 at 18:40
  • In this case entity.name is not readonly. Is there an easy way to create an object literal with readonly properties? – Philip Holly Jan 06 '22 at 19:08
  • @PhilipHolly I don't see what that has to do with `new class`? `entity.name` wasn't readonly with class syntax either. But yes, you can create object literals with readonly properties, e.g. `{ get name() { return "…"; }}`, `Object.defineProperty({ name: "…" }, "name", { readonly: true })` or `Object.defineProperties({}, {name: { value: "…", readonly: true} })`. – Bergi Jan 06 '22 at 20:11
  • @Bergi thanks. It wasn't explicit in the question, but the fact he made a getter method for the property caused me to think about it. Object literals are great, but classes do have some advantages. I should mention I use TypeScript and there's syntax for declaring variables as readonly or private. – Philip Holly Jan 07 '22 at 22:39
  • @PhilipHolly For typescript, [you can use `as const` with object literals](https://stackoverflow.com/q/56541293/1048572), or just declare the interface inline. But if you want a singleton with information hiding, I recommend using a module with named exports instead. – Bergi Jan 07 '22 at 23:39
  • @Bergi This answer is almost definitely going to make many people think that they should never use an anonymous class. Is that what you intended? – cesoid Jul 30 '22 at 04:32
  • @cesoid Yes that's what I intended, is "*don't use it ever*" not clear enough? – Bergi Jul 30 '22 at 11:07
  • @cesoid Did you mean "*anonymous class instance*" or "*anonymous class*"? The latter is fine, if it's meant to be instantiated multiple times. – Bergi Jul 30 '22 at 11:09
  • @Bergi The former and the latter would be included. Is "anonymous class" not clear enough? – cesoid Jul 30 '22 at 16:07
  • @cesoid Then sorry, I misunderstood your comment, no I don't think this will make people thing they shouldn't use anonymous classes - the question and answer talk specifically about the instantiation pattern. But anonymous classes are in general a bad idea as well, I don't see why you wouldn't name your class. – Bergi Jul 30 '22 at 17:23
  • @Bergi The answer would have made *me* think that I should never use an anonymous class if I didn't spend ten or fifteen minutes trying to understand why it was worded so strongly. I couldn't tell if the answer was really just addressing that particular style or something more general. Anyway, here's my use case: I have a lot of classes that I might someday turn into named classes, and some that I already have, and I want my higher level code to be able to treat them all the same. (The classes are created once, stored in a set, and then chosen at random to be instantiated.) – cesoid Jul 30 '22 at 19:59
  • @cesoid Ok I've tried to clarify the Q/A a bit. Since you're putting your classes in a set (and will use a class any number of times?), instead of immediately instantiating them with `new`, you're fine. Although I don't see a reason why you wouldn't name them - just write `set.add(class MyX {…})` instead of `set.add(class {…})` to give them an appropriate name. This will greatly aid in debugging. – Bergi Jul 30 '22 at 20:07
12

You might want anonymous classes if you know exactly what you're doing, you're creating a hierarchy of classes (i.e. things you want copies of) in a well-thought-out metaprogramming system, and there's no other elegant solution to extension, e.g.

{
    myImplementation: class extends MyBaseClass {
        someMethod(x) {
            super().someMethod(x);
            insert extended behavior
        }
    }
}

Of course you could implement the above with some abusive magic functions which use Object.assign:

{
    myImplementation: extendMagic(mySuper => ({
        someMethod(x) {
            mySuper.someMethod(x);
            insert extended behavior
        }
    }))
}

or find some better way to do what you're doing. But contrived use-cases will occasionally (though rarely) exist.

The use-cases are never great, but are most compelling when you need Class features which are harder to write with prototypical inheritance (and of course since Classes are sort of wrappers around prototypical inheritance, your use case boils down to wanting the syntactic sugar plus es6+ class features... do you want constructors and super and extends and staticmethod etc.... or not? Are you stuck working with classes which already exist, or can you write everything using Objects and asserts? And does it really need to be anonymous? These questions may help you decide.).

ninjagecko
  • 88,546
  • 24
  • 137
  • 145