Push functions and get callback - javascript

I have a basic widget which i can push function calls to (almost like Google analytics, ga.js)
Here is the widget code:
var widget = function () {
function _private_setName(a, callback) {
console.log(a[0]);
callback(a[0]);
}
return{
setName:_private_setName
};
}();
if (window._test) {
for (var i = 0; i < _test.length; i++) {
var method = _test[i].shift();
try {
widget[method].apply(widget, _test);
}
catch(err) { }
}
}
window._test = {
push: function() {
try {
var args = Array.prototype.slice.call(arguments, 0);
var method = args[0].shift();
widget[method].apply(widget, args);
}
catch(err) { }
}
};
So what i can currently do is this:
var _test = _test || [];
_test.push(['setName', 'Todd']);
However i would like to be able to get callbacks from the function setName.
I've tried:
_test.push('setName', 'Todd', function(num) {
console.log("callback called! " + num);
});
But i cannot get it to work, any ideas how i can implement this?

You should change
var method = args[0].shift();
to
var method = args.shift();
After that the callback will be called. Here is a jsfiddle with a working version http://jsfiddle.net/krasimir/pLuad/1/

That's some pretty hanky janky code you've got there to achieve what you're looking to do. A common practice with callback is to use arguments[arguments.length -1], in the function you are passing the callback to, so it's always the "last" argument that will be used as the callback function. Then you say
if(typeof arguments[arguments.length - 1] === 'function'){
arguments[arguments.length - 1](dataToPassToCallback);
}
In your situation, it seems like you are adding a lot of needless abstraction and making this much more difficult than it needs to be. For example, you are declaring a "widget" object/class, and then you are assigning static instances of itself to it ( widget[fnName] = widget.apply()) - so now when you are declaring more widgets, they are all containing references to the other widget methods.
I would imagine what you really want is for Widget class to be it's own thing and for there to be a WidgetManager class or a Widgets class that will then do similar things to what your _test array is doing.

Related

Spy function with elementary JavaScript syntax [duplicate]

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.
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.

How function reference works in js?

Recently I've been trying to use pixi.js for some fun project and I come across a concept that I do not understand at all. Quoting some code:
PIXI.loader
.add([
"images/one.png",
"images/two.png",
"images/three.png"
])
.on("progress", loadProgressHandler)
.load(setup);
function loadProgressHandler(loader, resource) {
console.log(`loading: ${resource.url}`);
};
How these arguments (loader, resource) are passed to the function since we only pass the reference to it in the event listener? Can someone show a generic implementation beneath that concept?
Lets say we have a function called callMe that just prints a number that its given:
function callMe(number) {
console.log(`I'm number: ${number}`);
}
callMe(2);
We can create a new variable to that same function, and call the newly created variable. This is possible since it's pointing to the same function that we've created earlier.
const callMeAswell = callMe;
callMe(3);
callMeAswell(4);
In short, this is what's happing inside the PIXI loaders, except for that it's stored somewhere else for you. Lets create a class to store the numbers and the function that we want to call:
function SomeLoader(){
this.numbers = []; // list of numbers we want to store for later usage
this.func = null; // function that we want to call when we're done loading
}
SomeLoader.prototype.add = function(number) {
this.numbers.push(number); // add the number to the list of numbers
}
SomeLoader.prototype.on = function(func) {
this.func = func; // just store the function for now, but don't do anything with it
}
SomeLoader.prototype.pretendToLoad = function() {
for(const number of this.numbers) {
this.func(number); // now we're going to call the function that we've stored (callMe in the example below)
}
}
const loader = new SomeLoader();
loader.add(5);
loader.add(6);
loader.on(callMe);
loader.pretendToLoad();
Or fluently:
function SomeLoader(){
this.numbers = [];
this.func = null;
}
SomeLoader.prototype.add = function(number) {
this.numbers.push(number);
return this;
}
SomeLoader.prototype.on = function(func) {
this.func = func;
return this;
}
SomeLoader.prototype.pretendToLoad = function() {
for(const number of this.numbers) {
this.func(number);
}
}
new SomeLoader()
.add(7)
.add(8)
.on(callMe)
.pretendToLoad();
Looks almost the same as the PIXI loaders, doesn't it? :)
Arguments are passed to the function when it is called.
The code which calls that function isn't in the question. It is done somewhere behind the on function.
In short: The same way as normal, you just aren't looking at the point where it happens.
const show = value => console.log(value);
const call_callback_with_hello_world = callback => callback("Hello, world");
call_callback_with_hello_world(show);
What #Quentin said is correct - adding on to that however...
A generic concept beneath that implemention is called a callback and would look like so:
function Loop(callback, index){
callback(index);
}
function CallbackFunction(val){
console.log(val)
}
for(var i = 0; i < 5; i++){
Loop(CallbackFunction, i);
}

How can rewrite function instead of reference?

var BigObject = (function() {
function deepCalculate(a, b, c) {
return a + b + c;
}
function calculate(x) {
deepCalculate(x, x, x);
}
return {
calculate: calculate,
api: {
deepCalculate: deepCalculate
}
}
})();
This is basic self executing function with private function I keep in api.
The problem I have is that now I can't overwrite deepCalculate from the outside of the function.
How is that a problem? I use Jasmine and want to test if function was called. For example:
spyOn(BigObject, 'calculate').andCallThrough();
expect(BigObject.api.deepCalculate).toHaveBeenCalled();
fails. However as I debug, I am sure that Jasmine binds BigObject.api.deepCalculate as a spy, however from the inside calculate still calls original deepCalculate function and not the spy.
I would like to know how can I overwrite the function and not just a reference for it.
The simple answer would be:
(function ()
{
var overWriteMe = function(foo)
{
return foo++;
},
overWrite = function(newFunc)
{
for (var p io returnVal)
{
if (returnVal[p] === overWriteMe)
{//update references
returnVal[p] = newFunc;
break;
}
}
overWriteMe = newFunc;//overwrite closure reference
},
returnVal = {
overWrite: overWrite,
myFunc: overWriteMe
};
}());
Though I must say that, I'd seriously think about alternative ways to acchieve whatever it is you're trying to do. A closure, IMO, should be treated as a whole. Replacing parts of it willy-nilly will soon prove to be a nightmare: you don't know what the closure function will be at any given point in time, where it was changed, what the previous state was, and why it was changed.
A temporary sollution might just be this:
var foo = (function()
{
var calc = function(x, callback)
{
callback = callback || defaultCall;
return callback.apply(this, [x]);
},
defaultCall(a)
{
return a*a+1;
},
return {calc: calc};
}());
foo(2);//returns 5
foo(2,function(x){ return --x;});//returns 1
foo(2);//returns 5 again
IMO, this is a lot safer, as it allows you to choose a different "internal" function to be used once, without changing the core behaviour of the code.

Javascript: Extend a Function

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.

Javascript function hooks

EDIT: OK, I believe the following solutions are valid:
Use the jQuery AOP plugin. It basically wraps the old function together with the hook into a function sandwich and reassigns it to the old function name. This causes nesting of functions with each new added hook.
If jQuery is not usable for you, just pillage the source code, there did not seem to be any jQuery dependencies in the plugin, and the source is simple and very small.
Have an object describing all hooks and their targets and one to store the initial unmodified function. When adding a new hook, the wrapping would be redone around the original function, instead of re-wrap the the previous wrapping function.
You escape nested functions, and get two objects to handle instead. Potentially, this could also mean easier hook handling, if you add/remove hooks often and out of order.
I'll go with the first, since it's already done, and I don't have performance to worry about. And since the original functions are not affected, even if I switch hooking methods, I'll only need to redo the hook adding, which might be just some simple search&replace operations.
Hi,
Is it possible to create a mechanism, in which function A might have a set of hooks(functions that will execute before/after function A)?
Ideally, function A would not be aware of hooking functionality, so that I do not have to modify the source code of function A to call the hooks. Something like:
A = function(){
alert("I'm a naive function");
};
B = function(){
alert("I'm having a piggyback ride on function A!"+
"And the fool doesn't even know it!");
};
addHook(B, A)//add hook B to function A
A()
//getting alerts "I'm a naive function"/"I'm having a
//piggyback ride on function A! And the fool doesn't even know it!"
I've been trying to hack something up for a couple of hours, but so far no luck.
Might not be pretty but it seems to work...
<script>
function A(x) { alert(x); return x; }
function B() { alert(123); }
function addHook(functionB, functionA, parent)
{
if (typeof parent == 'undefined')
parent = window;
for (var i in parent)
{
if (parent[i] === functionA)
{
parent[i] = function()
{
functionB();
return functionA.apply(this, arguments)
}
break;
}
}
}
addHook(B, A);
A(2);
</script>
Take a look at jQuery's AOP plugin. In general, google "javascript aspect oriented programming".
Very simple answer:
function someFunction() { alert("Bar!") }
var placeholder=someFunction;
someFunction=function() {
alert("Foo?");
placeholder();
}
This answer is not definitive, but rather demonstrative of a different technique than those offered thus far. This leverages the fact that a function in Javascript is a first-class object, and as such, a) you can pass it as a value to another function and b) you can add properties to it. Combine these traits with function's built-in "call" (or "apply") methods, and you have yourself a start toward a solution.
var function_itself = function() {
alert('in function itself');
}
function_itself.PRE_PROCESS = function() {
alert('in pre_process');
}
function_itself.POST_PROCESS = function() {
alert('in post_process');
}
var function_processor = function(func) {
if (func.PRE_PROCESS) {
func.PRE_PROCESS.call();
}
func.call();
if (func.POST_PROCESS) {
func.POST_PROCESS.call();
}
}
The following function will give you before and after hooks that can be stacked. So if you have a number of potential functions that need to run before the given function or after the given function then this would be a working solution. This solution does not require jQuery and uses native array methods (no shims required). It should also be context sensitive so if you are calling the original function with a context if should run each before and after function likewise.
// usage:
/*
function test(x) {
alert(x);
}
var htest = hookable(test);
htest.addHook("before", function (x) {
alert("Before " + x);
})
htest.addHook("after", function (x) {
alert("After " + x);
})
htest("test") // => Before test ... test ... After test
*/
function hookable(fn) {
var ifn = fn,
hooks = {
before : [],
after : []
};
function hookableFunction() {
var args = [].slice.call(arguments, 0),
i = 0,
fn;
for (i = 0; !!hooks.before[i]; i += 1) {
fn = hooks.before[i];
fn.apply(this, args);
}
ifn.apply(this, arguments);
for (i = 0; !!hooks.after[i]; i++) {
fn = hooks.after[i];
fn.apply(this, args);
}
}
hookableFunction.addHook = function (type, fn) {
if (hooks[type] instanceof Array) {
hooks[type].push(fn);
} else {
throw (function () {
var e = new Error("Invalid hook type");
e.expected = Object.keys(hooks);
e.got = type;
return e;
}());
}
};
return hookableFunction;
}
Here's what I did, might be useful in other applications like this:
//Setup a hooking object
a={
hook:function(name,f){
aion.hooks[name]=f;
}
}a.hooks={
//default hooks (also sets the object)
};
//Add a hook
a.hook('test',function(){
alert('test');
});
//Apply each Hook (can be done with for)
$.each(a.hooks,function(index,f){
f();
});
I don't know if this will be useful. You do need to modify the original function but only once and you don't need to keep editing it for firing hooks
https://github.com/rcorp/hooker

Categories

Resources