# Es5 class wrapping This wrapping implementation diverges from standard ES6 style wrapping. It also uses composition rather than inheritance, so it is easily pluggable. * For **NAPI** addons, `super()` can be called from C++ side. * Constructor is callable with `ClassName.call(obj, ...args)`. * Multiple C++ objects can be attached to a single JS object if it is necessary in an inheritance scenario. * On JS side `util.inherits` [is used](https://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor), and on C++ side there is `inheritEs5` function. ## Class Declaration ``` class ClassName { DECLARE_ES5_CLASS(ClassName, JSClassName); public: static void init(Napi::Env env, Napi::Object exports); explicit ClassName(const Napi::CallbackInfo& info); ~ClassName(); void _destroy(); private: JS_DECLARE_GETTER(ClassName, isDestroyed); JS_DECLARE_METHOD(ClassName, ClassName, destroy); bool _isDestroyed; }; ``` * `DECLARE_ES5_CLASS` - adds utility declarations, the first argument must be this class name, and the second argument will become the name (arbitrary) of this function (constructor) in JS. * `init` - can be used to initialize this class and export it. * `JS_DECLARE_METHOD` - declares a method, the first argument is this class, the second is the name of the method to be created. * `JS_DECLARE_GETTER` - declares a getter, the first argument is this class, the second is the name of the getter to be created. * `JS_DECLARE_SETTER` - declares a setter, the first argument is this class, the second is the name of the setter to be created. ## Class Implementation ``` IMPLEMENT_ES5_CLASS(ClassName); // Fill the properties and export the class void ClassName::init(Napi::Env env, Napi::Object exports) { Napi::Function ctor = wrap(env); JS_ASSIGN_METHOD(destroy); JS_ASSIGN_GETTER(isDestroyed); // ... exports.Set("JSClassName", ctor); } ClassName::ClassName(const Napi::CallbackInfo &info) { NAPI_ENV; super(info); _isDestroyed = false; // ... } ClassName::~ClassName() { _destroy(); } void ClassName::_destroy() { DES_CHECK; // ... _isDestroyed = true; } JS_IMPLEMENT_METHOD(ClassName, destroy) { THIS_CHECK; emit("destroy"); _destroy(); RET_UNDEFINED; } JS_IMPLEMENT_GETTER(ClassName, isDestroyed) { THIS_CHECK; RET_BOOL(_isDestroyed); } ``` * `IMPLEMENT_ES5_CLASS` - implements some utility functions for class wrapping. * `JS_ASSIGN_METHOD` - in `init()`, assigns the given method to this class. * `JS_ASSIGN_GETTER` - in `init()`, assigns the given getter to this class. * `JS_ASSIGN_SETTER` - in `init()`, assigns both getter and setter to this class. It also takes only one argument because both have the same name. * `JS_IMPLEMENT_METHOD` - implements a method, the first argument is this class, the second is the name of the method being implemented. * `JS_IMPLEMENT_GETTER` - implements a getter, the first argument is this class, the second is the name of the getter being implemented. * `JS_IMPLEMENT_SETTER` - implements a setter, the first argument is this class, the second is the name of the setter being implemented.