Javascript: inheriting encapsulated variables - javascript

Edit: Removed higher-level ideas, included problem-specific and less-transferable code.
I implemented my DAL using DAO's. My application hooks in to various databases (mostly for legacy reasons). In order to facilitate efficient and intelligent usage of connections, I use a ConnectionBroker singleton to manage the various connections that may (or may not be) open. This ConnectionBroker is then injected into the DAO's where they can request control of a particular connection object, request new connections, ect.
From an inheritence POV, I'd like something like:
AbstractDbConnection
|-- MongoDbConnection
|-- MsSqlConnection
|-- CouchDbConnection
|-- ...
Where AbstractDbConnection defines an interface, and implements some shared event-based logic.
var EventEmitter = require('events').EventEmitter;
module.exports = function AbstractDbConnection(host, port, database, login, ...) {
// private
var state = StatesEnum.Closed; // StatesEnum = {Open: 0, Closed: 1, ..}; Object.freeze(StatesEnum);
// api that must be overwritten
this.connect = function connect() {throw new ...}
this.disconnect = function disconnect() {throw new ...}
... <more>
this.getState = function() { return state; }
}
AbstractDbConnection.prototype.__proto__ = EventEmitter.prototype;
And then I implement the interface using driver-specific code:
var mssqldriver = require('mssqldriver'), //fictitious driver
AbstractDbConnection = require(__dirname + '/blah/AbstractDbConnection');
module.exports = function MsSqlConnection(host, port, database, login, ...) {
var me = this;
// implement using driver
this.connect = function connect() {...}
this.disconnect = function disconnect() {...}
... <more>
driverSpecificConnection.on('driverSpecificOpenEvent', function() {
me.emit('open'); // relay driver-specific events into common events
state = StatesEnum.Open; // how ??
}
...
}
MsSqlConnection.prototype.__proto__ = new AbstractDbConnection();
But clearly I want to protect the state property from changing inadvertently.

Just listen for the open event in the "abstract" constructor!
var EventEmitter = require('events').EventEmitter;
module.exports = AbstractDbConnection;
var StatesEnum = module.exports.StatesEnum = Object.freeze({
Open: 0, Closed: 1, …
});
function AbstractDbConnection(host, port, database, login, …) {
// private
var state = StatesEnum.Closed;
EventEmitter.call(this);
this.getState = function() { return state; }
this.on('open', function(e) {
state = StatesEnum.Open;
});
}
AbstractDbConnection.prototype = Object.create(EventEmitter.prototype);
// api that must be overwritten
AbstractDbConnection.prototype.connect = function connect() {throw new …};
AbstractDbConnection.prototype.disconnect = function disconnect() {throw new …};
var Mssqldriver = require('mssqldriver'), //fictitious driver
AbstractDbConnection = require(__dirname + '/blah/AbstractDbConnection');
module.exports = MsSqlConnection;
function MsSqlConnection(host, port, database, login, …) {
AbstractDbConnection.call(this);
this.driver = new Mssqldriver(…);
this.driver.on('driverSpecificOpenEvent', this.emit.bind(this, 'open'));
…
}
MsSqlConnection.prototype = Object.create(AbstractDbConnection.prototype);
MsSqlConnection.prototype.connect = function connect() {…};
MsSqlConnection.prototype.disconnect = function disconnect() {…};

You can use the module pattern to do this.
var transport_module = function() {
var mileage = 0; // private
return {
transport : function(distance) {
mileage += distance;
}
};
}
//use it
var car = transport_module(),
boat = transport_module(),
motorcycle = transport_module();
car.transport(10);
boat.transport(5);
motorcycle.transport(20);
The variable mileage is not visible to any other javascript code. Like a private java/C++ class variable. However, I would think about whether you need this kind of protection. I use modules a lot but not for small objects like class instances in java/C++.

Related

Passing socket.io instance to JS object constructor

I read this question and attempted to do the solution, however I am trying to pass my instance of io to an object constructor instead of a class. I originally attempted to do something like...
//index.js
const {CONNECTION, CREATE_ROOM} = require('./SignalTypes')
const app = require('express')()
const server = require('http').Server(app)
const io = require('socket.io')(server)
const Lobbies = require('./lobby')
let lobbies = new Lobbies(io)
io.of('/menu').on(CONNECTION, (socket) => {
console.log(`User connected to main menu`)
socket.on(CREATE_ROOM, () => {
const roomKey = lobbies.createLobby()
socket.emit(ROOM_CREATED, roomKey)
})
...
})
And my Lobbies file looks like...
//lobby.js
const shortid = require('shortid')
function Lobbies(io) {
this.io = io;
this.lobbies = {}
}
Lobbies.prototype.createLobby = () => {
let roomKey = shortid.generate()
//create namespace for new lobby
const lobbyNamespace = this.io.of(`/${roomKey}`) // issue
this.lobbies[roomKey] = new Lobby(roomKey, lobbyNamespace)
return roomKey
}
//Lobby object constructor defined later
...
module.exports = Lobbies
However I keep running into errors in which it says io is undefined at the line
//lobby.js
const lobbyNamespace = this.io.of(`/${roomKey}`)
//TypeError: Cannot read property 'of' of undefined
I was wondering if there's a way to pass my io object to my object constructor without having to change it into an ES6 class or something. Any suggestions?
You are losing this reference when using arrow function syntax. I don't know why do you want to use old, hard-to-read syntax, but if you want that instead of class you should do:
Lobbies.prototype.createLobby = function() {
let roomKey = shortid.generate()
//create namespace for new lobby
const lobbyNamespace = this.io.of(`/${roomKey}`) // issue
this.lobbies[roomKey] = new Lobby(roomKey, lobbyNamespace)
return roomKey
}

calling a function object to load your js

function FriendlyChat() {
// statements
}
FriendlyChat.protoype.somemethod = function() {
// statements
};
FriendlyChat.protoype.somemethod2 = function() {
//statements
};
window.onload = function() {
window.friendlyChat = new FriendlyChat();
};
So i noticed the above structure for js while working on a google codelab.
And I have two ques.
in normal objects you have to call the function i.e Object.somemethod()
How does this structure call the methods assigned to it.
From my limited understanding, Firendlychat.protoype.the method treats the
function as an object and the methods are passed to the new object created on
window.onload.Via
inheritance, The object created i.e friendlychat has all these methods.
Yet none of the methods are called in any way. How does this work?
Is there any advantage to structuring your code in this way other than
readability
Note :
Main function
function FriendlyChat() {
this.checkSetup();
// Shortcuts to DOM Elements.
this.messageList = document.getElementById('messages');
this.messageForm = document.getElementById('message-form');
// Saves message on form submit.
this.messageForm.addEventListener('submit', this.saveMessage.bind(this));
this.signOutButton.addEventListener('click', this.signOut.bind(this));
this.signInButton.addEventListener('click', this.signIn.bind(this));
// Toggle for the button.
var buttonTogglingHandler = this.toggleButton.bind(this);
this.messageInput.addEventListener('keyup', buttonTogglingHandler);
this.messageInput.addEventListener('change', buttonTogglingHandler);
// Events for image upload.
this.submitImageButton.addEventListener('click', function(e) {
e.preventDefault();
this.mediaCapture.click();
}.bind(this));
this.mediaCapture.addEventListener('change',
this.saveImageMessage.bind(this));
this.initFirebase();
}
//the methods are setup here
// Sets up shortcuts to Firebase features and initiate firebase auth.
FriendlyChat.prototype.initFirebase = function() {
this.auth = firebase.auth();
this.database = firebase.database();
this.storage = firebase.storage();
// Initiates Firebase auth and listen to auth state changes.
this.auth.onAuthStateChanged(this.onAuthStateChanged.bind(this));
};
// Saves a new message on the Firebase DB.
FriendlyChat.prototype.saveMessage = function(e) {
e.preventDefault();
}
};
FriendlyChat.prototype.setImageUrl = function(imageUri, imgElement) {
imgElement.src = imageUri;
};
// Saves a new message containing an image URI in Firebase.
// This first saves the image in Firebase storage.
FriendlyChat.prototype.saveImageMessage = function(event) {
event.preventDefault();
var file = event.target.files[0];
// Clear the selection in the file picker input.
this.imageForm.reset();
// Check if the file is an image.
if (!file.type.match('image.*')) {
var data = {
message: 'You can only share images',
timeout: 2000
};
this.signInSnackbar.MaterialSnackbar.showSnackbar(data);
return;
}
// Check if the user is signed-in
if (this.checkSignedInWithMessage()) {
// TODO(DEVELOPER): Upload image to Firebase storage and add message.
}
};
// Signs-in Friendly Chat.
FriendlyChat.prototype.signIn = function() {
var provider = new firebase.auth.GoogleAuthProvider();
this.auth.signInWithRedirect(provider);
};
// Signs-out of Friendly Chat.
FriendlyChat.prototype.signOut = function() {
this.auth.signOut();
};
One of the advantages I've seen when using prototype inheritance was that you can control all instances of an object. For ex:
function FriendlyChat() {
this.chatIsActive = true;
}
FriendlyChat.prototype.deactivateChat = function(...rooms) {
for (chatRoom of rooms) {
chatRoom.chatIsActive = false;
}
};
var chat1 = new FriendlyChat();
var chat2 = new FriendlyChat();
var chatController = new FriendlyChat();
chatController.deactivateChat(chat1, chat2)
console.log(chat1.chatIsActive)
In ES6, however, you can do it:
class FriendlyChat {
constructor() {
this.chatIsActive = true;
}
static deactivateChat(...rooms) {
for (let chatRoom of rooms) {
chatRoom.chatIsActive = false;
}
}
}
var chat1 = new FriendlyChat();
var chat2 = new FriendlyChat();
FriendlyChat.deactivateChat(chat1, chat2)
console.log(chat1.chatIsActive)
And the another advantage of using prototype is that you can save memory spaces when you make an object from new keyword. For instance, the code in ES5 above, you can see chat1 and chat2 I've made by using new. Then chat1 and chat2 will be able to access deactivateChat() method which is in a sharing-space. It's because of the concept, called prototype-chaining.
And the next ES6 version is just a syntactic sugar - under the hood it does the same as ES5 version
I post this as a reference to others who have been faced with this dilemma.
First of all, ONe of the core issues for me was migrating from java, I seemed to be familiar territory but things work a bit different in js.I strongly recommend these links:
Objects in Detail
js Prototype
So the key to why this method works is due to the
window.friendlyapp =new friendlychat()
Now normally in most languages you have an object
obj() {
attr : value
method: function() {}
}
And then to use the method you do
var child = new obj();
child.method();
but in this method the var is made an instance of the window object and thats why none of the methods of the app need to be explicitly called.

Angular 1.5: multiple WebSocket connections

I'm trying to create a service or factory using Angular 1.5 (with ES6) where I could have multiple instances of it, each one having a different connection to a WebSocket (the main purpose of this is a chat system).
I was able to do a service that works for a single WebSocket connection, but given the purpose of this project, I need to be able to connect to different "rooms" but each one of them has a URL with different connection parameters (like so: ws://localhost:8080/chat/<param1>/<param2>).
I'm using angular-websocket (https://github.com/AngularClass/angular-websocket). Since I'm using ES6 with strict mode, I have to inject $websocket from this lib and create immediately an instance of it on the constructor.
So, what I'm looking for is: being able to create multiple WebSocket connections, ideally in a service/factory, where each one of them has its own connection parameters (which would be given on the controller where this service will be instantiated), and then each instance would be able to manage the sending/receiving of new respective "room" messages.
Using ES5, I could probably create a non-singleton service or factory and that could probably solve this problem, but as I'm learning ES6 I would really love to have this solved that way.
Here's my current Chat service class, which currently only is able to handle a static connection, and it's a singleton.
export default class ChatService {
constructor($websocket) {
'ngInject';
this._$websocket = $websocket('wss://localhost:8080/chat' + '/param1/param2');
this.collection = [];
this.init();
}
init() {
this._$websocket.onMessage(this.onMessage);
this._$websocket.onOpen(this.onOpen);
this._$websocket.onClose(this.onClose);
this._$websocket.onError(this.onError);
}
onOpen() {
console.log('Connection open');
}
onClose(event) {
console.log('Connection closed: ', event);
}
onError(event) {
console.log('Connection Error: ', event);
}
onMessage(message) {
this.collection.push(JSON.parse(message.data));
}
closeSocket() {
this._$websocket.close();
}
sendMessage(text) {
// Code to send a message using this connection
}
}
If you have any other suggestion on how to tackle this problem, I'm all ears.
Thank you.
I use jquery atmosphere js for multi socket connection. You can use it.
Exapmle multi connection code :
HTML
<button id="b1">
ping s1
</button>
<button id="b2">
ping s1
</button>
<div id="s1">
<h1>s1 pings</h1>
<p></p>
</div>
<div id="s2">
<h1>s2 pings</h1>
<p></p>
</div>
JS:
var container;
function Request(sU) {
this.url = sU;
this.contentType = 'application/json';
this.logLevel = 'debug';
this.trackMessageLength = false;
this.enableProtocol = false;
this.enableXDR = true;
this.transport = 'websocket';
this.fallbackTransport = 'sse';
this.reconnectInterval = 5000;
this.connectTimeout = 30000;
this.timeout = 60000;
this.maxReconnectOnClose = 3;
this.isDetail = false;
this.suspend = true;
//this.headers = {device: $rootScope.imageType}
this.onOpen = function(response) {
console.log("connected");
};
this.onReopen = function(response) {};
this.onMessage = function(response) {
$(container).append("<br>" + response.responseBody );
console.log(response)
};
this.onClientTimeout = function(request) {};
this.onReconnect = function(request, response) {};
this.onError = function(response) {};
this.onClose = function(response) {};
};// Request
function SocketConnector(sU) {
return {
request: new Request(sU),
socket: null,
closeSocket: function(aciklama) {
this.socket.close();
}, //closeSocket
connectSocket: function() {
this.socket = $.atmosphere.subscribe(this.request);
} //connectSocket
};
};
var socket1 = new SocketConnector('https://echo.websocket.org');
socket1.connectSocket();
$("#b1").click(function(){
container = "#s1";
socket1.socket.push(Date.now())
});
var socket2 = new SocketConnector('https://echo.websocket.org');
socket2.connectSocket();
$("#b2").click(function(){
container = "#s2";
socket2.socket.push(Date.now())
});
You can write this in any angular service js.
Look at JS Fiddle example.

How to include one .js file into another in Node.js? [duplicate]

I'm writing a simple server for Node.js and I'm using my own class called User which looks like:
function User(socket) {
this.socket = socket;
this.nickname = null;
/* ... just the typical source code like functions, variables and bugs ... */
this.write = function(object) {
this.socket.write(JSON.stringify(object));
}
};
and then later in the process I'm instantiating it a lot:
var server = net.createServer(function (socket) {
/* other bugs */
var user = new User(socket);
/* more bugs and bad practise */
});
Can I move my User class definition to another javascript file and "include" it somehow?
You can simply do this:
user.js
class User {
//...
}
module.exports = User // 👈 Export class
server.js
const User = require('./user.js')
let user = new User()
This is called CommonJS module.
ES Modules
Since Node.js version 14 it's possible to use ES Modules with CommonJS. Read more about it in the ESM documentation.
user.mjs (👈 extension is important)
export default class User {}
server.mjs
import User from './user.mjs'
let user = new User()
Using ES6, you can have user.js:
export default class User {
constructor() {
...
}
}
And then use it in server.js
const User = require('./user.js').default;
const user = new User();
Modify your class definition to read like this:
exports.User = function (socket) {
...
};
Then rename the file to user.js. Assuming it's in the root directory of your main script, you can include it like this:
var user = require('./user');
var someUser = new user.User();
That's the quick and dirty version. Read about CommonJS Modules if you'd like to learn more.
Another way in addition to the ones provided here for ES6
module.exports = class TEST{
constructor(size) {
this.map = new MAp();
this.size = size;
}
get(key) {
return this.map.get(key);
}
length() {
return this.map.size;
}
}
and include the same as
var TEST= require('./TEST');
var test = new TEST(1);
If you append this to user.js:
exports.User = User;
then in server.js you can do:
var userFile = require('./user.js');
var User = userFile.User;
http://nodejs.org/docs/v0.4.10/api/globals.html#require
Another way is:
global.User = User;
then this would be enough in server.js:
require('./user.js');

How to dispatch custom messages across Javascript classes in an efficient way?

I have built loosely coupled components for a javascript client application where these components send and receive messages via a manager class:
a component detects an event => send to manager
manager receives an event => send to everyone
any component got message => interested in message? yes: process, no: discard.
This works as intended, but not efficient. Here is the implementation of manager:
in Livescript:
class mgr
~>
#actor-list = []
register: (actor) ->
#actor-list ++= [actor]
dispatch: (msg) ->
for actor in #actor-list
actor.inbox-put msg
in Javascript:
var mgr;
mgr = (function(){
mgr.displayName = 'mgr';
var prototype = mgr.prototype, constructor = mgr;
function mgr(){
var this$ = this instanceof ctor$ ? this : new ctor$;
this$.actorList = [];
return this$;
} function ctor$(){} ctor$.prototype = prototype;
prototype.register = function(actor){
return this.actorList = this.actorList.concat([actor]);
};
prototype.dispatch = function(msg){
var i$, ref$, len$, actor, results$ = [];
for (i$ = 0, len$ = (ref$ = this.actorList).length; i$ < len$; ++i$) {
actor = ref$[i$];
results$.push(actor.inboxPut(msg));
}
return results$;
};
return mgr;
}());
I have searched the net for "event dispatching in Javascript" and there is a couple of projects used for this purpose, but some of them seems dead:
https://github.com/mrdoob/eventdispatcher.js/
Some of them uses same for loop under the hood:
https://github.com/krasimir/EventBus
and some of them requires binding on an html node:
https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events
What I need is pure javascript communication between Javascript classes. Is there any efficient/native way to achieve this?

Categories

Resources