I am writing vanilla javascript project. I have multiple independent components. I like them to communicate without coupling them. Event based message bus is ideal for me. I implemented something trivial like following and I would like to ask whether is there any existing library that can do this more efficiently or whether language itself provides any capabilities to achieve this or not?
PS: I do not have any dom events in this case. I would like to create my own events so that I can write components pretty generic and clean way. I think React has similar concept and I will check that later on but for now I like to use vanilla javascript.
Thanks!
// event message bus interface
define(function(require) {
"use strict";
function CustomEventDispatcher() {
this._subscribers = {}
CustomEventDispatcher.prototype.on = function(event, callback) {
if(!this._subscribers[event])
this._subscribers[event] = [];
this._subscribers[event].push(callback);
}
CustomEventDispatcher.prototype.trigger = function(event, params) {
if (this._subscribers[event]) {
for (let i in this._subscribers[event]) {
this._subscribers[event][i](params);
}
}
}
CustomEventDispatcher.Instance = null;
CustomEventDispatcher.GetInstance = function () {
if (!CustomEventDispatcher.Instance) {
CustomEventDispatcher.Instance = new CustomEventDispatcher();
}
return CustomEventDispatcher.Instance;
}
return CustomEventDispatcher;
});
// UI interaction triggers or backend worker triggers event
let params = {
new_dir : '/dat',
};
CustomEventDispatcher.GetInstance().trigger('onUpdateDataSource', params);
// Directory Module registers directory update events and updates itself
function DirectorLister() {
CustomEventDispatcher.GetInstance().on('onUpdateDirectoryListing', (params) => this.change_content(params));
}
In my case, I'm using the Phaser framework.
So in this example I'm extending the Group class of phaser. Every 'actor' class (Sprite, Group, ...) calls upon the update() prototype every few miliseconds.
My idea was to extend this function only when the application runs on a desktop (so not on a phone).
for example:
var MousePointer = function (game, parent, name) {
Phaser.Group.call(this, game, parent, name);
this.init();
};
MousePointer.prototype = Object.create(Phaser.Group.prototype);
MousePointer.prototype.constructor = MousePointer;
MousePointer.prototype.init = function () {
// ... init
};
MousePointer.prototype.update = function () {
// Do something when on desktop
};
I can't possibly use an if clausule in the update() function to check whether the player is on dekstop/tablet/phone. So is there a way to actually override the prototype on initialisation?
for example (pseudocode):
if(onPhone)
MousePointer.prototype.update = parent.prototype.update;
else
MousePointer.prototype.update = this.update;
Well, you've kind of already written the answer for yourself, haven't you? This code (not inside the init method).
if(onPhone) {
MousePointer.prototype.update = function(){//Phone implementation};
} else {
MousePointer.prototype.update = function(){//Other implementation};
}
I advise against starting off with the "regular" function and then potentially overriding it, since you're just declaring it for nothing.
I think a better way to do this would be to write two different classes that shares the same parent, and then write different update() implementations for them. Then you can just do something like:
if(phone) {
var obj = new PhoneMousePointerObject();
} else {
var obj = new DesktopMousePointerObject();
}
// ... later
obj.update()
I'm trying to create a javascript library like jquery. I get how to create a normal library like so:
var lib=lib||(function () {
function privateFunction (alert ("hi");){};
return {
exampleAlert: function(input){
alert(input);
}
}
})();
Calling it like so:
lib.exampleAlert ("test");
This is like jquery
$.ajax(stuffhere);
My question revolves around jquery. It can call the dom like $('.class').hide() and have functions like $.ajax(stuffhere); in the same library. How can I do dom calls and a regular function call like the ajax one in the above example library?
Thanks in advance!! Have searched more days than I would like to admit.
DOM has nothing to do here, it is just up to jQuery implementation.
If you ask about having both lib() and lib.func() calls, then you can do the following to support both function types at the same time:
var lib = function(sel) {
return {
object: document.querySelector(sel),
text: function(val) {
if (val === undefined) {
return this.object.innerText;
} else {
this.object.innerText = val;
}
}
};
};
lib.ajax = function() {
console.log("AJAX imitation");
};
Now, you can do both:
lib("body").text("hi"); // jQuery-style setter
var text = lib("body").text(); // jQuery-style getter, returns "hi"
and
lib.ajax();
jQuery works exactly in the same way, but hundred times more complex.
I'm reading and watching Tutorials about Meteor since 1-2 Weeks. I've learned about how to structure a meteor app regarding server and client side code, accounts, security etc.
What i could not figure out:
Where do i put the calculation logic properly?
For example:
A user puts data in a form and the data is saved in the database. Depending on this input data i want to do several calculations by putting the data through lets say a chaining of around 20 Methods, and finally display some results.
At the moment i have all of these Methods inside the file where the Template.displayResults.helper is.
When i put them in another file they don't get recognized, i think because of the wrapper Meteor puts around.
Example: I have a collection of DIY projects and each of the projects has a field with an array of utilities that are neccessary for the project.
Projects = new Mongo.Collection('projects');
/*
exampleProject = {
"name": "Kitchen table",
"utilities": ["Hammer", "Glue"]
}
*/
I want to display all possible DIY projects depending on the utilities the user has checked.
The UI has a group of checkboxes via the user can select a bunch of utilities he wants to use.
These values are saved in a collection.
Utilities = new Mongo.Collection('utilities');
/*
exampleUtility = {
"name": "Hammer",
"checked": true
}
*/
Then i want to calculate the possible Projects...
Template.displayResults.helpers({
projectsPossible: function () {
var utilitiesCheckedDB = Utilities.find({
checked: true
}).fetch();
var projectsAll = Projects.find().fetch();
return projectsPossible(utilitiesCheckedDB, projectsAll);
}
});
// Returns an array of all possible projects depending on the selected utilities
function projectsPossible(utilitiesCheckedDB, projectsAll) {
var result = [];
_.each(projectsAll, function (project) {
if (project.utilities.length === _.intersection(project.utilities, checkedCheckboxesList(utilitiesCheckedDB)).length) {
result.push(project);
}
});
return result;
}
// Returns an array of all checked utilities in the current checkbox database
function checkedCheckboxesList(checkedCheckboxesDB) {
var result = [];
_.each(checkedCheckboxesDB, function (checkbox) {
result.push(checkbox.name);
});
return result;
}
The question is: There are more methods like "projectsPossible" and "checkedCheckboxesList". Where do i put these methods to get a good structure?
Thanks in advance!
Vin
If you want to register global helpers, just use Template.registerHelper(name, function), for instance:
Template.registerHelper('projectsPossible', function() {
var utilitiesCheckedDB = Utilities.find({
checked: true
}).fetch();
var projectsAll = Projects.find().fetch();
return projectsPossible(utilitiesCheckedDB, projectsAll);
});
If you want to make the functions projectsPossible(utilitiesCheckedDB, projectsAll) or checkedCheckboxesList(checkedCheckboxesDB) accessible from other (client) files, you can make them global. For example:
projectsPossible = function(utilitiesCheckedDB, projectsAll) {
var result = [];
_.each(projectsAll, function(project) {
if (project.utilities.length === _.intersection(project.utilities, checkedCheckboxesList(utilitiesCheckedDB)).length) {
result.push(project);
}
});
return result;
};
You can make model classes, using the transform option for collections. For an ES5 example, see the docs: http://docs.meteor.com/#/full/mongo_collection
Also, you have to make that model class or function global by not using var.
(function() {
foo = function foo() {
alert("fooh")
}
})()
In the above example, without foo =, the foo function would only be visible inside its own file because of the wrapper.
The main reason why I want it is that I want to extend my initialize function.
Something like this:
// main.js
window.onload = init();
function init(){
doSomething();
}
// extend.js
function extends init(){
doSomethingHereToo();
}
So I want to extend a function like I extend a class in PHP.
And I would like to extend it from other files too, so for example I have the original init function in main.js and the extended function in extended.js.
With a wider view of what you're actually trying to do and the context in which you're doing it, I'm sure we could give you a better answer than the literal answer to your question.
But here's a literal answer:
If you're assigning these functions to some property somewhere, you can wrap the original function and put your replacement on the property instead:
// Original code in main.js
var theProperty = init;
function init(){
doSomething();
}
// Extending it by replacing and wrapping, in extended.js
theProperty = (function(old) {
function extendsInit() {
old();
doSomething();
}
return extendsInit;
})(theProperty);
If your functions aren't already on an object, you'd probably want to put them there to facilitate the above. For instance:
// In main.js
var MyLibrary = {
init: function init() {
}
};
// In extended.js
(function() {
var oldInit = MyLibrary.init;
MyLibrary.init = extendedInit;
function extendedInit() {
oldInit.call(MyLibrary); // Use #call in case `init` uses `this`
doSomething();
}
})();
But there are better ways to do that. Like for instance, providing a means of registering init functions.
// In main.js
var MyLibrary = (function() {
var initFunctions = [];
return {
init: function init() {
var fns = initFunctions;
initFunctions = undefined;
for (var index = 0; index < fns.length; ++index) {
try { fns[index](); } catch (e) { }
}
},
addInitFunction: function addInitFunction(fn) {
if (initFunctions) {
// Init hasn't run yet, remember it
initFunctions.push(fn);
} else {
// `init` has already run, call it almost immediately
// but *asynchronously* (so the caller never sees the
// call synchronously)
setTimeout(fn, 0);
}
}
};
})();
Here in 2020 (or really any time after ~2016), that can be written a bit more compactly:
// In main.js
const MyLibrary = (() => {
let initFunctions = [];
return {
init() {
const fns = initFunctions;
initFunctions = undefined;
for (const fn of fns) {
try { fn(); } catch (e) { }
}
},
addInitFunction(fn) {
if (initFunctions) {
// Init hasn't run yet, remember it
initFunctions.push(fn);
} else {
// `init` has already run, call it almost immediately
// but *asynchronously* (so the caller never sees the
// call synchronously)
setTimeout(fn, 0);
// Or: `Promise.resolve().then(() => fn());`
// (Not `.then(fn)` just to avoid passing it an argument)
}
}
};
})();
There are several ways to go about this, it depends what your purpose is, if you just want to execute the function as well and in the same context, you can use .apply():
function init(){
doSomething();
}
function myFunc(){
init.apply(this, arguments);
doSomethingHereToo();
}
If you want to replace it with a newer init, it'd look like this:
function init(){
doSomething();
}
//anytime later
var old_init = init;
init = function() {
old_init.apply(this, arguments);
doSomethingHereToo();
};
The other methods are great but they don't preserve any prototype functions attached to init. To get around that you can do the following (inspired by the post from Nick Craver).
(function () {
var old_prototype = init.prototype;
var old_init = init;
init = function () {
old_init.apply(this, arguments);
// Do something extra
};
init.prototype = old_prototype;
}) ();
Another option could be:
var initial = function() {
console.log( 'initial function!' );
}
var iWantToExecuteThisOneToo = function () {
console.log( 'the other function that i wanted to execute!' );
}
function extendFunction( oldOne, newOne ) {
return (function() {
oldOne();
newOne();
})();
}
var extendedFunction = extendFunction( initial, iWantToExecuteThisOneToo );
2017+ solution
The idea of function extensions comes from functional paradigm, which is natively supported since ES6:
function init(){
doSomething();
}
// extend.js
init = (f => u => { f(u)
doSomethingHereToo();
})(init);
init();
As per #TJCrowder's concern about stack dump, the browsers handle the situation much better today. If you save this code into test.html and run it, you get
test.html:3 Uncaught ReferenceError: doSomething is not defined
at init (test.html:3)
at test.html:8
at test.html:12
Line 12: the init call, Line 8: the init extension, Line 3: the undefined doSomething() call.
Note: Much respect to veteran T.J. Crowder, who kindly answered my question many years ago, when I was a newbie. After the years, I still remember the respectfull attitude and I try to follow the good example.
This is very simple and straight forward. Look at the code. Try to grasp the basic concept behind javascript extension.
First let us extend javascript function.
function Base(props) {
const _props = props
this.getProps = () => _props
// We can make method private by not binding it to this object.
// Hence it is not exposed when we return this.
const privateMethod = () => "do internal stuff"
return this
}
You can extend this function by creating child function in following way
function Child(props) {
const parent = Base(props)
this.getMessage = () => `Message is ${parent.getProps()}`;
// You can remove the line below to extend as in private inheritance,
// not exposing parent function properties and method.
this.prototype = parent
return this
}
Now you can use Child function as follows,
let childObject = Child("Secret Message")
console.log(childObject.getMessage()) // logs "Message is Secret Message"
console.log(childObject.getProps()) // logs "Secret Message"
We can also create Javascript Function by extending Javascript classes, like this.
class BaseClass {
constructor(props) {
this.props = props
// You can remove the line below to make getProps method private.
// As it will not be binded to this, but let it be
this.getProps = this.getProps.bind(this)
}
getProps() {
return this.props
}
}
Let us extend this class with Child function like this,
function Child(props) {
let parent = new BaseClass(props)
const getMessage = () => `Message is ${parent.getProps()}`;
return { ...parent, getMessage} // I have used spread operator.
}
Again you can use Child function as follows to get similar result,
let childObject = Child("Secret Message")
console.log(childObject.getMessage()) // logs "Message is Secret Message"
console.log(childObject.getProps()) // logs "Secret Message"
Javascript is very easy language. We can do almost anything. Happy JavaScripting... Hope I was able to give you an idea to use in your case.
as I understand it, you are trying to fetch the applications connected to the user account. You can do this by making a request on the API, I don't know if discord.js covers this part of the API
endpoint: https://discord.com/api/users/#me/connections
Request type: GET Header:
Authorization: "Beareryou token"
response: [
{...}
]
Use extendFunction.js
init = extendFunction(init, function(args) {
doSomethingHereToo();
});
But in your specific case, it's easier to extend the global onload function:
extendFunction('onload', function(args) {
doSomethingHereToo();
});
I actually really like your question, it's making me think about different use cases.
For javascript events, you really want to add and remove handlers - but for extendFunction, how could you later remove functionality? I could easily add a .revert method to extended functions, so init = init.revert() would return the original function. Obviously this could lead to some pretty bad code, but perhaps it lets you get something done without touching a foreign part of the codebase.