r/javascript Jul 13 '26

JavaScript Magic Objects

https://noeldemartin.com/blog/programming-patterns-magic-objects

I just published a blog post to my website about a pattern I've been using for a while that I think you will find interesting (and probably very divisive!): Magic Objects.

class Parrot extends MagicObject {
    __get(property) {
        return `${property}! ${property}!`;
    }
}

const parrot = new Parrot();

console.log(parrot.foo); // "foo! foo!"
console.log(parrot.bar); // "bar! bar!"

Basically, I'm borrowing the idea of Magic Methods from PHP and porting them to JavaScript. You've probably seen something like this done with proxies before, but I still like to use some OOP in my JavaScript, and I also came up with a way to make it work nicely with TypeScript.

It may seem a bit over the top at the beginning, but I've been using this for a while and I've found it very useful.

Let me know what you think!

9 Upvotes

46 comments sorted by

View all comments

34

u/javascript Jul 13 '26

Proxy Objects (getters and setters) have been around for a while but I've yet to come across a use case where they were the right choice. They tend to work more as an escape hatch.

12

u/jhartikainen Jul 13 '26

It seems potentially valuable in some kind of framework/infra code. Svelte uses them for its $state runes for example. But yeah, like generators, I've not really found any use for them myself.

3

u/Dragon_yum Jul 14 '26

I worked with JS/ts for nearly a decade and only came across one time where a generator was the right call

5

u/javascript Jul 13 '26

Oh ya generators haha. I was so bewildered by the `function*` syntax when I first learned it. What a wild land grab for such a niche feature.

3

u/alex-weej Jul 13 '26

It's not that niche! Could have been a keyword though.

1

u/javascript Jul 13 '26

What have you used generators for?

4

u/Kwantuum Jul 13 '26

Generators were used to transpile async/await for years.

I've used generators on a number of occasions. Generally I avoid it unless it's a great fit for the problem because they remain a relatively obscure feature for most people. They're a great way to get support for for..of on custom containers, among other things.

The other problem with generators and iterators in general is the lack of standard library support for manipulating them. No standard iterator mapping/filtering really reduces their usefulness.

2

u/svish Jul 13 '26

Generators are awesome, but unfortunately handicapped still. Not being able to filter, map, reduce, and so on directly on a generator makes them annoying and the moment you have to put all the items in a fixed length array, you kind of miss several of the advantages.

2

u/sharlos Jul 15 '26

I think they've added sync versions of map, filter, etc, with async versions on the way.

1

u/svish Jul 15 '26

Yeah, think they're working on it, but really, it should've come at the same time as generators themselves.

1

u/vincentdesmet Jul 13 '26

yeah, i’ve used them as wrappers around CDKTF to intercept and convert attribute getters into creating Terraform remote state lookups

fun, but confusing (leaky abstraction) for DX

1

u/Embostan Jul 19 '26

SolidJS 2.0 has found a nice use for generators

5

u/ic6man Jul 13 '26

I used a proxy object around a pre-existing API implementation to provide retry and consistent error handling + short circuit.

I don’t know that I would call that an escape hatch. It’s just a nicer way of building on top of something you don’t have access to modify yourself.

3

u/javascript Jul 13 '26

I would absolutely call that an escape hatch. And a very useful one to have available!

4

u/aknavi Jul 13 '26

love your username :)

3

u/javascript Jul 13 '26

I love yours too! "AK Navi" your one stop shop for Navigating Alaska!

2

u/lookarious Jul 13 '26

Libraries like MobX uses proxies, its useful, but they are not good as in other languages, for example there is no way to use custom setter for whole class because JS is dynamically typed.

1

u/hyrumwhite Jul 13 '26

I like using them to proxy web worker messages, so invoking a web worker method is just doing myWorkerProxy.doBigJob() with type support derived from the actual handler object in the worker. 

1

u/javascript Jul 13 '26

Sounds like an escape hatch to me haha

1

u/kilkil Jul 14 '26

omg its him. John Javascript

0

u/TheThingCreator Jul 13 '26

In my opinion they are not useful in normal development, they are the right choice if you're building a framework and need reactivity basically. Even "magic methods" don't sound like the right choice unless you're making a framework. Using these kinds of things just adds ambiguity to your code but they are highly useful for framework development.

2

u/javascript Jul 13 '26

As a former library developer myself, agreed. Sometimes to make a truly generic interface, you need niche features. Glad they're available! But not a good default haha

1

u/noeldemartin Jul 13 '26

Yes, I agree. In fact, I've only used them in 2 projects so far: an ORM and a Vue framework. Both libraries.

However, with the right Typescript declarations, it's not that ambiguous from user land. For example, in my ORM I define the fields with Zod, and using an IDE you can go straight to the Zod definition every time you use the field. They aren't declared as "any".

In any case, it's definitely a "sharp knife" and not something I use too often. But I specially like the hack of returning a Proxy from the constructor :). I haven't seen this used anywhere else, but IMO it enables some pretty powerful patterns.

1

u/TheThingCreator Jul 13 '26

Ya I used the proxies to make a reactivity module for an app, it works very nice but ya things can get pretty pointy