Access `this` from within required object literal? - javascript

I desire to have the following type of object:
const Client = require('./Client')
let client = new Client()
client.someObject.create(...)
client.someObject.update(...)
client.someObject.delete(...)
etc.
This is very easy to accomplish doing something like this:
const Client = function () {
this.someObject = {}
this.someObject.create = function () {...}
this.someObject.update = function () {...}
this.someObject.delete = function () {...}
}
module.exports = Client
But from an organizational standpoint (and because of the massive number of functions someObject has, it would be helpful to put all the someObject stuff into it's own file and require it: require('./someObject'). However, I still need to be able to access the Client object (this) within someObject.create(), someObject.update(), etc.
this.someObject = require('./someObject')
// someObject.js
module.exports = {
create: function () {
// How do I access Client here? Can I pass it to the object literal?
}
}
I've tried to do some prototype sub module type of setup but it doesn't appear to work.
Client.prototype.someObject.create = function () { ... }
How can I separate someObject into it's own file and still access the Client this?

You'll need to provide the Client instance to someObject itself so the latter's methods can use it to reference the former.
One way you accomplish that is to define a 2nd constructor for someObject that takes the client as an argument.
const SomeObject = function (client) {
if (!client) throw new Error('Client reference is required.');
this.client = client;
};
SomeObject.prototype.create = function () {
let client = this.client;
// ...
};
// ....
module.exports = SomeObject;
const SomeObject = require('./someObject');
const Client = function () {
this.someObject = new SomeObject(this);
}
You can also get a similar result with Object.create() if you'd rather keep the object literal:
const baseline = {
create: function () {
let client = this.client;
// ...
},
// ...
};
module.exports = function createSomeObject(client) {
return Object.create(baseline, {
client: {
value: client
}
});
};
const createSomeObject = require('./someObject');
const Client = function () {
this.someObject = createSomeObject(this);
};

Related

Exporting multiple functions with arguments

All I am trying to do is to export two functions from a module. One function taking an argument and the other with no argument:
function initClass(params)
{
return new Promise( (resolve, reject) => {
if (!wallet) {
wallet = new WalletClient(params);
resolve(wallet);
} else {
console.log('Wallet is initialized');
resolve(wallet);
}
});
}
function getInstance()
{
return wallet;
}
For initClass(params) only, I can do this as:
module.exports = (params) => {
initClass(params)
}
And then I call this as:
var init = require('./class.js')(params).initClass(params);
This works fine.
Now, for me to export getInstance() as well, I have tried to do the following but it doesn't seem to work.
module.exports = (params) => {
initClass(params),
getInstance
}
This complaints that there is no function getInstance.
Then I tried this:
module.exports.init = (params) => {
initClass(params)
}
module.exports.instance = {
getInstance
}
Then call them as:
var init = require('./class.js').init(params).initClass(params);
What is the proper way to export multiple functions like this?
Thank you.
You're making it more complex than needed. Once you have your functions defined, you can export it with this:
module.exports = {
initClass,
getInstance
}
To use it, you do this:
const init = require("./class.js");
init.initClass(params);
const instance = init.getInstance();
What you're exporting from the module is an object (which I've named init in the example above) that contains two functions. You don't have to pass arguments to the functions at the time you require.
module.exports is basically an object with keys which can refer to any variables/functions of your file.In your case,
module.exports.initClass = function (params){
...
}
module.exports.getInstance = function (){
}
When importing it
var init = require('./class.') // init object has two keys -> initClass and getInstance
init.initClass('abc')
init.getInstance()
If i'm understanding correctly you are trying to export multiple methods if that is the case simple use this.
module.exports = {
method: function() {},
otherMethod: function(parmas) {}
}
In your code use like this.
var init = require('./class.js');
init.method()
init.otherMethond(paramObj)
If you want below scenario you need to check out about method chaining.
var init = require('./class.js').init(params).initClass(params);

How to bind "this" automatically while calling a function?

My example code:
var Person = (function () {
var __sym = Symbol('Person');
class Person {
constructor(name) {
this[__sym] = { name: name };
}
getName() {
let _this = this[__sym];
return _this.name;
}
}
return Person;
}());
var person = new Person('Hermione');
console.log(person.name); // undefined
console.log(person.getName()); // Hermione
In this example, I'd use __sym as a key to assign to the private data.
My question is: How to bind this[__sym] to every method inside the Person class?
My real project:
let Chatwindow = (function () {
let __sym = Symbol('Chatwindow');
let __data = {};
// for typo
let __prop = {
targetUserId: 'targetUserId'
};
__data.init = function (...args) {
let _this = this[__sym];
let options = args[0];
// validating the type of 'options' and the properties...
// just get what I need
_this[__prop.targetUserId] = options[__prop.targetUserId];
(async () => {
let messages = await __data.getMessagesAsync.call(_this);
// my goal:
// let messages = await __data.getMessagesAsync();
})();
};
__data.getMessagesAsync = function () {
let _this = this;
let promise = new Promise(function (done) {
// create model before sending
let model = { [__prop.targetUserId]: _this[__prop.targetUserId] };
// sending...
done();
});
return promise;
};
class Chatwindow {
constructor() {
this[__sym] = {};
}
set init(value) {
return __data.init;
}
get init() {
return (...args) => __data.init.call(this, ...args);
}
}
return Chatwindow;
}());
Everytime I call a method, I have to use call(_this) function to bind the key, like this:
let messages = await __data.getMessagesAsync.call(_this);
After that, inside the getMessagesAsync method, I can assign to the private data using this property.
What I want to achieve: I want to bind all of the methods just one time inside the init method. How can I do that?
Something like this:
__data.getMessagesAsync.oncall = function () {
// bind this with this[__sym]
};
Then,
__data.getMessagesAsync(); // no need to pass anymore
Thank you!
You can use arrow functions, so you will be sure that context (this) will be same every time (this will be pointing to parent this no matter from where arrow function is called)
__data.getMessagesAsync = () => {
let promise = new Promise((done) => {
// create model before sending
let model = { [__prop.targetUserId]: this[__prop.targetUserId] };
// sending...
done();
});
return promise;
}
In javascript, using function_name.bind(o) allows you to create a new function whose context this is bound to the object o.
What you want is to create a new function:
__data.boundMessagesFunction = __data.getMessagesAsync.bind(_this);
Now you can call:
let messages = await __data.boundMessagesFunction();

How to access object.prototype methods from another file using module.exports?

If I want to use an object and its methods in another file, how would I set up my module.exports?
Object:
var Object = function ()
{
...
}
Object.prototype.foo = function (param)
{
...
}
Module.export:
module.exports = {
Object : Object
}
or
module.exports = {
Object : Object,
foo : Object.prototype.foo
}
?
A few ways of doing this but if you're trying to access prototype methods from your other file, then you'll need to instantiate your constructor,
something like:
For ex:
// lib.js
var YourThing = function () {
}
YourThing.prototype.someMethod = function () {
console.log('do something cool');
}
module.exports = YourThing;
// index.js
var YT = require('./lib.js');
var yourThing = new YT();
yourThing.someMethod();
module.exports = Object;
This will export your Object as a Module.
If your object is not renewed in your app, the best way to use it as an executed function with late binding of its prototype methods
const _ = require('lodash')
var Object = function ()
{
..
_.bindAll(this); // at last bind all methods. this way you won't miss a method
}
Object.prototype.foo = function (param)
{
...
}
module.exports = new Object();
then you can call the functions like,
const myObj = require('./object-file')
myObj.myMethod();
If you need reusable component,
module.exports = Object;
const _obj = require('./object-file'); // you can call this way anywhere in any function and for every require, it creates a new object.
var object = new _obj();
_obj.anyMethod();

In node.js ES6, is it possible to pass in a type and then instantiate it?

In my project I have several classes that look like this:
"use strict";
var exports = module.exports = {};
var SystemsDAO = require('./dao/systems/SystemsDAO.js');
var aop = require('./dbAOPUtils.js');
var Proxy = require('harmony-proxy');
var sqlite3 = require('sqlite3').verbose();
/* Wraps a SystemServiceObject and passes in a constructed
* DAO object as an argument to specified functions. */
exports.SystemsDAOIntercepter = function(obj) {
let handler = {
get(target, propKey, receiver) {
const origMethod = target[propKey];
return function(...args) {
console.log('systemDAOIntercepter: BEGIN');
// Create a reportsdao object and proxy it through an dbSQLiteConnectionIntercepter
// (So we don't have to create it for every single method)
var systemdao = new SystemsDAO('blah');
var proxSystemDAO = aop.dbSQLiteConnectionIntercepter(systemdao, sqlite3.OPEN_READONLY);
args.push(proxSystemDAO);
console.log('propKey: ' + target[propKey]);
let result = null;
result = origMethod.apply(this, args);
console.log('systemsDAOIntercepter: END');
return result;
};
}
};
return new Proxy(obj, handler);
};
Is it possible to pass in a type for an argument so that I only need a single DAOIntercepter class, and not one for each data access object?
I can see the part where I require() the SystemsDAO working for this by passing the file name, but as for instantiation of that class, I can't really see how it would be possible to do that.
Sure - you can pass classes around like any other variable in javascript.
Note that DAOType is provided and instantiated inside the method, now.
"use strict";
var exports = module.exports = {};
var aop = require('./dbAOPUtils.js');
var Proxy = require('harmony-proxy');
var sqlite3 = require('sqlite3').verbose();
/* Wraps a SystemServiceObject and passes in a constructed
* DAO object as an argument to specified functions. */
exports.makeInterceptor = function(DAOType, obj) {
let handler = {
get(target, propKey, receiver) {
const origMethod = target[propKey];
return function(...args) {
console.log('systemDAOIntercepter: BEGIN');
// Create a reportsdao object and proxy it through an dbSQLiteConnectionIntercepter
// (So we don't have to create it for every single method)
var dao = new DAOType('blah');
var proxSystemDAO = aop.dbSQLiteConnectionIntercepter(dao, sqlite3.OPEN_READONLY);
args.push(proxSystemDAO);
console.log('propKey: ' + target[propKey]);
let result = null;
result = origMethod.apply(this, args);
console.log('makeInterceptor: END');
return result;
};
}
};
return new Proxy(obj, handler);
};
I have to admit that I would (personally) prefer to see the class instantiated externally and injected in through the arguments, however, instead of creating it inline.

Get reference to method function by name?

I want to store a function, internal to the function-object its within, in an object member, but I need to get access to it via name. The code below makes it easier to understand...
// MyClassThing.js:
var MyClassThing = (function() {
var _ref = {obj: undefined, fnc: undefined};
function setup(domObject, refName) {
_ref.obj = domObject;
_ref.fnc = this['func_' + refName]; // <<-- This does not work!!
}
function doThing() {
if(_ref.func)
_ref.fnc();
}
function func_foo() {
console.log('Foo!');
}
return {
setup: setup,
doThing: doThing
};
})();
// index.html
<script>
MyClassThing.setup($('#fooObj'), 'foo');
MyClassThing.doThing();
</script>
What do I do to get _ref.fnc = ???? to work properly?
You will have to use helper object to put methods as its properties. Then you will be able to refer to them by variable name:
var MyClassThing = (function () {
var _ref = { obj: undefined, fnc: undefined },
methods = {};
function setup(domObject, refName) {
_ref.obj = domObject;
_ref.fnc = methods['func_' + refName];
}
function doThing () {
if (_ref.fnc) _ref.fnc();
}
methods.func_foo = function () {
console.log('Foo!');
};
return {
setup: setup,
doThing: doThing
};
})();
You can't use this because it points to the object returned from IIFE, however your methods of interest are not properties of this object.
There's a typo in your code:
var MyClassThing = (function() {
var _ref = {obj: undefined, fnc: undefined};
function setup(domObject, refName) {
_ref.obj = domObject;
_ref.fnc = this['func_' + refName]; // <<-- This does not work!!
}
function doThing() {
if(_ref.fnc)
_ref.fnc();
}
function func_foo() {
console.log('Foo!');
}
return {
setup: setup,
doThing: doThing
};
})();
In your doThing function, you are checking for the existency of a _ref.func instead of _ref.fnc
To achieve what you want to do, you need to understand that the functions you are declaring using the "function" are not linked to the class. There's no notion of "private member function" in javascript. If you want to bind a function to a class, you need to declare it like this (there are other ways, i'm just showing you one of them) :
MyClassThing.prototype.func_foo = function () {
}
The best thing to do, in your case, would be to set _ref.fnc to func_foo directly. If you want to keep the this context, take a look at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call

Categories