Skip to content

Instantly share code, notes, and snippets.

@gabrielschulhof
Last active September 19, 2018 18:44
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save gabrielschulhof/377d1cf557794efc324d3c9a13c834e9 to your computer and use it in GitHub Desktop.
Save gabrielschulhof/377d1cf557794efc324d3c9a13c834e9 to your computer and use it in GitHub Desktop.
Doing extends on the native side
#include <stdio.h>
#include <node.h>
static void
NativeClassConstructor(const v8::FunctionCallbackInfo<v8::Value>& info) {
}
static void
NativeClassProtoMethod(const v8::FunctionCallbackInfo<v8::Value>& info) {
fprintf(stderr, "NativeClassProtoMethod was called\n");
}
static v8::Local<v8::Value>
CreateNativeClassLocal(v8::Isolate* isolate, bool createMethod) {
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::FunctionTemplate> nativeClass =
v8::FunctionTemplate::New(isolate, NativeClassConstructor);
if (createMethod) {
v8::Local<v8::FunctionTemplate> nativeClassProtoMethod =
v8::FunctionTemplate::New(isolate, NativeClassProtoMethod,
v8::Local<v8::Value>(),
v8::Signature::New(isolate, nativeClass));
nativeClass->PrototypeTemplate()
->Set(isolate, "classMethod", nativeClassProtoMethod);
}
return nativeClass->GetFunction(context).ToLocalChecked();
}
static void
CreateNativeClass(const v8::FunctionCallbackInfo<v8::Value>& info) {
info.GetReturnValue().Set(CreateNativeClassLocal(info.GetIsolate(), true));
}
static void
SubclassMe(const v8::FunctionCallbackInfo<v8::Value>& info) {
// Cannot use FunctionTemplate::Inherit because we don't have the
// FunctionTemplate for info[0].
v8::Isolate* isolate = info.GetIsolate();
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::Value> subclass = CreateNativeClassLocal(isolate, false);
v8::Local<v8::Value> superclass = info[0];
v8::Local<v8::Value> subProto = subclass.As<v8::Object>()
->Get(context,
v8::String::NewFromUtf8(isolate, "prototype", v8::NewStringType::kNormal)
.ToLocalChecked()).ToLocalChecked();
v8::Local<v8::Value> superProto = superclass.As<v8::Object>()
->Get(context,
v8::String::NewFromUtf8(isolate, "prototype", v8::NewStringType::kNormal)
.ToLocalChecked()).ToLocalChecked();
subProto.As<v8::Object>()
->Set(context,
v8::String::NewFromUtf8(isolate, "__proto__", v8::NewStringType::kNormal)
.ToLocalChecked(),
superProto).FromJust();
info.GetReturnValue().Set(subclass);
}
static void Init(v8::Local<v8::Object> exports,
v8::Local<v8::Value> module,
v8::Local<v8::Context> context) {
v8::Isolate* isolate = context->GetIsolate();
exports->Set(context,
v8::String::NewFromUtf8(isolate, "subclassMe", v8::NewStringType::kNormal)
.ToLocalChecked(),
v8::FunctionTemplate::New(isolate, SubclassMe)
->GetFunction(context).ToLocalChecked()).FromJust();
exports->Set(context,
v8::String::NewFromUtf8(isolate, "createNativeClass",
v8::NewStringType::kNormal).ToLocalChecked(),
v8::FunctionTemplate::New(isolate, CreateNativeClass)
->GetFunction(context).ToLocalChecked()).FromJust();
}
NODE_MODULE_CONTEXT_AWARE(NODE_GYP_MODULE_NAME, Init)
{
'targets': [
{
'target_name': 'binding',
'sources': [ 'binding.cc' ]
}
]
}
const binding = require('./build/Debug/binding');
function subclassMe(superclass) {
class Subclass extends superclass {
}
return Subclass;
}
const JSSuperClass = class {
classMethod() {
console.log("JS Superclass prototype method was called");
}
};
const NativeSuperClass = binding.createNativeClass();
// scenario 1: Superclass was created by JS and subclassing is performed by JS
const JSSubClassOfJSSuperClass = subclassMe(JSSuperClass);
(new JSSubClassOfJSSuperClass()).classMethod();
// scenario 2: Superclass was created by native and subclassing is performed by JS
const JSSubClassOfNativeSuperClass = subclassMe(NativeSuperClass);
(new JSSubClassOfNativeSuperClass()).classMethod();
// scenario 3: Superclass was created by JS and subclassing is performed by native
const NativeSubClassOfJSSuperClass = binding.subclassMe(JSSuperClass);
(new NativeSubClassOfJSSuperClass()).classMethod();
// scenario 4: Superclass was created by native and subclassing is performed by native
const NativeSubClassOfNativeSuperClass = binding.subclassMe(NativeSuperClass);
(new NativeSubClassOfNativeSuperClass()).classMethod();
{
"name": "test-inheritance2",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment