JS-Magic
JavaScript magic methods support.
We know that ES6 brings the capability of Proxy that allows us observing an
object, and setters ang getters are build-in support in JavaScript, but if we
need to build those things every time, that's just mess and pain. With this
package, you can define setters and getters, along with other functions, right
in the class definition itself, and when instantiating the class, the instance
will always have the the benefits of the magical calling functionalities.
This package is inspired by PHP magic methods, and currently supports these
methods: __get
, __set
, __has
, __delete
, __invoke
. Other methods like
toString
and toJSON
are built-in support in JavaScript.
Install
npm i js-magic
In Deno
Just import this package directly:
import { applyMagic } from "https://deno.land/x/js_magic/index.ts";
Example
import { applyMagic, MagicalClass } from "js-magic";
@applyMagic
export class Car implements MagicalClass {
name!: string;
wheels?: number;
constructor(name?: string, wheels?: number) {
if (name !== undefined) this.name = name;
if (wheels !== undefined) this.wheels = wheels;
}
__get(prop: string | symbol): any {
return prop in this ? this[prop]
: (prop == "name" ? this.constructor.name + " Instance" : null);
}
__set(prop: string | symbol, value: any): void {
this[prop] = prop == "name" ? value + " Instance" : value;
}
__has(prop: string | symbol): boolean {
return (typeof prop != "string" || prop.slice(0, 2) != "__")
&& (prop in this || prop == "name");
}
__delete(prop: string | symbol): void {
if (prop.slice(0, 2) == "__" || prop == "name") return;
delete this[prop];
}
static __invoke(...args: any[]): any {
return "invoking Car as a function";
}
}
How It Works?
The decorator applyMagic
is a function that returns a highly-customized ES5
pseudo-class, it will replace the original class, so that when instantiating,
the magic methods will be auto-applied to the instance wrapped by a Proxy
.
Since applyMagic
is a function, so if you're coding in JavaScript without
decorator support, you can manually call it to generate the wrapping class and
assign to the old one. Like this:
import { applyMagic } from "js-magic";
class Car {
}
Car = applyMagic(Car);
Since the returned class is wrapped in ES5 style, so that it allows you calling
it as a function, where the __invoke
method will called under the hood.
Support of Inheritance
This package also supports native inheritance, allows you inheriting the magical
calling functionalities from a super class to sub-classes. Also you can rewrite
the magic methods in the sub-class, and call the super's via super
keyword.
NOTE: this feature DOESN'T work with __invoke
, unless using applyMagic
on
the sub-class as well.
Support of Objects Other Than Class
Since v1.1, this package also supports other objects other than class, if
calling applyMagic
on a non-function object, it will returns a proxy of the
original object that supports magic functions. Moreover, if you want this
feature be apply to a function, you can pass the second argument proxyOnly
to
applyMagic
, and it will not treat the function as a potential class.
Additional Symbols
This package also provides symbols according to the magic method names (__get
,
__set
, __has
, __delete
, __invoke
), you can use them if you want to hide
the methods from IDE IntelliSense, but generally they are not common used.
Supported Environments
Any environment that supports ES6 Proxy
will work with this package perfectly,
generally, NodeJS 6.0+
, Deno and modern browsers (IE
aside) should support
Proxy
already.
In browsers, if you're not using any module resolution, access the global
variable window.magic
instead.
More Examples
For more examples, please check out the Test.