Reputation: 73005
(Disclaimer: Deleted previous question that led to some new fundamental problems, so trying again with a more sensible question).
I've got a class that has some required initialization properties:
var CustomRequest = require('./request'),
ok = require('objectkit'),
helpers = require('../helpers')
var MySDKClient = function(orgId, appId) {
var self = this
if (ok(orgId).exists() && ok(appId).exists()) {
self.orgId = orgId
self.appId = appId
return self
} else {
throw new Error('orgId and appId must be passed during initialization')
}
}
MySDKClient.prototype = {
GET: function(uri, options, callback) {
return new CustomRequest('GET', uri, options, callback)
}
}
// Exports
module.exports = MySDKClient
This works as-is like so:
var MySDKClient = require('./lib/client')
var client = new MySDKClient('orgId', 'appId')
But I need to wrap this in a new class the holds a single instance of MySDKClient
and inherits all of its methods/properties. We'll call it MySDK
, and it needs to have a custom initializer method:
var MySDK = require('./mysdk')
MySDK.initialize('orgId', 'appId')
module.exports = MySDK
(Or less preferred):
var MySDK = require('./lib/client').initialize('orgId', 'appId')
module.exports = MySDK
I want it to fail to initialize (and therefore fail to call any of MySDKClient
's methods) by way of the throw
in MySDKClient
if the initialize method has not been called.
For example, this should work:
var MySDK = require('./lib/client')
MySDK.initialize('orgId', 'appId')
MySDK.GET('...') // should work!
And this should not:
var MySDK = require('./lib/client')
MySDK.GET('...') // should throw error because of 'throw new Error()`
// that already exists in MySDKClient -- more accurately,
// MySDK should be null or undefined because it wasn't initialized.
How would I do this? I've tried using util.inherits()
and Object.create()
to create a 'subclass', but no matter what I do, the prototype methods from the MySDKClient class either aren't accessible, or they work whether or not the client has been properly initialized.
Update: Trying out @sg.cc's solution, MySDKClient behaves just fine more/less like it did before, but I still can't init the MySDK instance in a module properly:
// mysdk.js
var MySDKClient = require('./lib/client'),
ok = require('objectkit'),
helpers = require('./helpers'),
util = require("util")
function MySDK() {
// new MySDKClient?
}
MySDK.prototype = {
initialize: function(orgId, appId) {
return new MySDKClient(orgId, appId)
}
}
// Should I still be doing this?
// util.inherits(MySDK, MySDKClient)
// Exports
module.exports = new MySDK
Calling it:
var MySDK = require('./mysdk')
MySDK.initialize('peter', 'wolf')
MySDK.GET() // undefined is not a function
Upvotes: 0
Views: 77
Reputation: 13105
You need to stop thinking in terms of classes and start embracing the prototypal inheritance of javascript. Also please try to simplify the code snippets to the bare minimum to make it easy to reproduce.
I have simplified your example for reproducibility but the following should point you to the right direction:
Here is my simplified MySDKClient constructor:
var MySDKClient = function(orgId) { this.orgId = orgId; }
MySDKClient.prototype.GET = function() { alert(this.orgId); }
Your MySDK does not have to be a constructor (or a class
if you prefer):
var MySDK = {
initialize: function(orgId) {
Object.setPrototypeOf(MySDK, new MySDKClient(orgId))
}
}
Try it out in the console:
MySDK.GET()
Will throw an error because when the interpreter walks up the prototype chain of MySDK it does not find GET function.
Now if you call MySDK.initialize(10);
the prototype chain of the object is modified to encorporate MySDKClient. And now if you run MySDK.GET()
you will see 10 being alerted.
While Object.setPrototypeOf
is a new addition to javascript, there is a very simple polyfill available using Object.prototype.__proto__
that work on pretty much all major platforms
Upvotes: 2
Reputation: 1826
var CustomRequest = require('./request'),
ok = require('objectkit'),
helpers = require('../helpers')
var MySDKClient = function(org, app){
return (function init(orgId, appId) {
var init = false;
if( ok(orgId).exists() && ok(appId).exists() ) {
this.orgId = orgId;
this.appId = appId;
init = true;
} else {
throw new Error('orgId and appId must be passed during initialization')
}
if( !init ) return;
return {
GET: function(uri, options, callback){
// Where are you using orgId that customRequest needs to fail if they aren't present?
return new CustomRequest('GET', uri, options, callback);
}
}
})(org, app);
}
module.exports = MySDKClient;
To test:
var MySDK = require('./lib/client');
var a = MySDK(123, abc);
var b = MySDK(); // -> Exception thrown
a.GET(some, args, here); // Works
b.GET(some, args, here); // property GET of undefined is not a function
Upvotes: 1