I have got this code which register a callback method.
function BaseClass() {
var context = this;
(function initialize() {
context.registerField(context.Name, function updateValues(Name, value) {
context.Value = value;
});
})();
}
This is how the callback methods are being called.
updateValues.call(null, names, values);
The issue is the registerfield() is called multiple times with different context.
When the call back are being called they are not getting executed on correct context. How can I invoke the callback on correct objects?
updateValues.call(null, names, values);
Related
I originally come from the Java Programming language, and I was just wondering why it is possible in javascript to pass a callback function as a variable or plain object (without parameters) to another function, and then use this callback function inside of another function but this time with parameters to pass.
And how exactly is this callback returning my user object, as I did not specify a return function inside callback(user), or specify any function body at all for my callback. Is this done inside the setTimeout(()...) function as the timeoutHandler implementation is implicitly returning something?
var getUser = (id,callback) => {
var user = {
id: id,
name: 'Vikram'
};
setTimeout(() => {
callback(user);
},3000);
};
getUser(31, (userObject) => {
console.log(userObject);
});
I see two questions here:
why it is possible in javascript to pass a callback function as a variable or plain object (without parameters) to another function.
Because functions are first-class objects, we can pass a function as an argument in another function and later execute that passed-in function or even return it to be executed later.
Read more here: https://javascriptissexy.com/understand-javascript-callback-functions-and-use-them/
Below shows functions are just objects as well:
function hello() {
return 'hello';
}
hello.other = 'world';
console.log(hello() + ', ' + hello.other);
how exactly is this callback returning my user object, as I did not specify a return function inside callback(user), or specify any function body at all for my callback.
setTimeout(()...) function is not implicitly returning anything, it just registers a function, that would execute later. When the function registered by the setTimeout triggers, it invokes the callback(user) and that resolves getUser registered function which logs to the console. Remember callbacks are asynchronous.
Functions have implicit returns if not specified, which returns undefined, meaning you did not explicitly return.
Below shows an example:
function hello() {
console.log('Hello, World');
}
console.log(hello()); // undefined.
function hi() {
return 'Hi, World';
}
console.log(hi()); // Hi, World.
The function i.e callback is passed as reference here. So you can pass it as much you want, when you call it then you can pass on the arguments and it will refer to original function.
And also it's not returning the user object, it's just consoling out the user object. As you have not used any return it will return undefined. Try consoling the callback fn return out.
var getUser = (id,callback) => {
var user = {
id: id,
name: 'Vikram'
};
setTimeout(() => {
console.log(callback(user), 'return value of callback');
},3000);
};
In javascript function is a object.
It behaves like function only with ()
So you can pass function to another function or variable as value.
Some functions in javascript are asynchronous.
setTimeout is such async function. It means callback function will be run after a time.
What's happening:
//assign anonymous function to variable
// until function without () it only a object
var getUser = (id,callback) => {
//set up params
var user = {
id: id,
name: 'Vikram'
};
// setup asynchronous function setTimeout
setTimeout(() => {
// run callback with params when time would done
callback(user);
},3000);
};
// call function which contains in getUser-variable and pass 2 params: int and callback-function
getUser(31, (userObject) => {
console.log(userObject);
});
function DoSomething()
{
var scope = this;
}
Consider the following methods of invoking it:
Option 1:
var self= this;
$someElement.change(self.DoSomething);
Option 2:
var self= this;
$someElement.change(function(){self.DoSomething();});
Why is it that the when the change event is triggered, the first line of code results in scope being the element that triggered the event, but the second results in a scope that is the same as self but the second?
Since I don't understand the concept at hand here, it has been difficult for me to Google the correct search term.
jQuery calls the given function within a context of original element.
Option 1:
You have passed self.DoSomething as a function.
jQuery will call self.DoSomething within a context of $someElement:
The following code is executed:
var self = this;
self.DoSomething.call($someElement);
function DoSomething()
{
// this = $someElement
var scope = this;
}
within DoSomething this is equal to callee - $someElement.
Option 2:
You have passed anonymous function as a function.
jQuery will call anonymous function within a context of $someElement:
var self = this;
function() {
self.DoSomething();
}.call($someElement);
function() {
// this = $someElement, as well
self.DoSomething(); // LOOK! You call self's method. Not within any context
}
function DoSomething()
{
// default function call, default this is presented
}
I intend to create a "preprocessual" function that is invoked right before a callback is invoked. In other words, invoking a callback should follow the pattern: preprocessual function -> callback. In order to "insert" such a preprocessual function, I could simply create a closure, rewrite the callback inside the closure so that the preprocessual function gets invoked, then at the end of that rewritten callback, invoke the original callback.
var end = function(init) {
/*
In here, init is processed.
Init contains multiple callbacks.
One callback is chosen to be invoked.
*/
init.callback();
};
var closure = function(init) {
var old = init.callback;
init.callback = function() {
/*
Do the preprocessual stuff
*/
console.log("The preprocessual functionality has now taken place.");
return old.apply(this, Array.prototype.slice.call(arguments));
};
return end.apply(this, Array.prototype.slice.call(arguments));
};
closure({
/*among other properties*/
callback: function() {
console.log("The preprocessual callback must have been invoked when 'end' invokes me.");
}
});
However, I have multiple callbacks, while I have only one preprocessual function. Each invocation of those callbacks should be preceded by an invocation of the same preprocessual function. In order to not have to write a preprocessual callback for each separate possible callback, I made a loop in the closure, that assigns the variable old to the next callback, then rewrote the callback using the Function constructor.
Everything still works. However, I am no longer able to use non global variables in my callback function that it could originally access. The following crashes, claiming that variable is not defined (as per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function).
(function() {
var end = function(init) {
/*
In here, init is processed.
Init contains multiple callbacks.
One callback is chosen to be invoked.
*/
init.callback();
};
var closure = function(init) {
var old = init.callback;
init.callback = new Function(
"\
/*\
Do the preprocessual stuff\
*/\
console.log(\"The preprocessual functionality has now taken place.\");\
return " + old + ".apply(this, Array.prototype.slice.call(arguments));\
"
);
return end.apply(this, Array.prototype.slice.call(arguments));
};
var variable = "value";
closure({
/*among other properties*/
callback: function() {
console.log("The preprocessual callback must have been invoked when 'end' invokes me.");
console.log(variable);
}
});
})();
So then I thought, let's try to bind the variables I need in my callback to the callback function. I then encountered a very strange problem. For some reason binding a scope/parameters to the callback function (with which the Function constructor has little to do), results in strange errors. A small example of such an error:
This works
var callback = function() {
console.log(arguments);
};
callback = new Function(
"\
return " + callback + ".apply(this, Array.prototype.slice.call(arguments));\
"
);
callback(1, 2, 3);
This does not work
var callback = function() {
console.log(arguments);
}.bind(this);
callback = new Function(
"\
return " + callback + ".apply(this, Array.prototype.slice.call(arguments));\
"
);
callback(1, 2, 3);
It does not matter if I assign the callback to another variable, such as old, in between and use old in the Function constructor and it doesn't matter if I use a completely different bound function inside the Function constructor, either. Any bound function (whether referenced to with a variable or not) gives me the error: "SyntaxError: missing ] after element list".
In fact, even this fails
callback = new Function(
"\
return " + (function() {}.bind(this)) + ".apply(this, Array.prototype.slice.call(arguments));\
"
);
callback(1, 2, 3);
And I fail to figure out why this is the case. Useful help would be appreciated.
As requested, the actual use case:
var
ajax = function(init) {
for (var i = 0, callbacks = ["success", "error"]; i < callbacks.length; i++) {
if (init.hasOwnProperty(callbacks[i] + "Callback")) {
init[callbacks[i] + "Callback"] = new Function("responseText",
"\
/*\
Preprocessual callback takes place here (among other things, messages from the server are inserted in the document)\
*/\
\
return " + init[callbacks[i] + "Callback"] + ".apply(this, Array.prototype.slice.call(arguments));\
"
);
}
}
// This is the actual ajax function, which can operate independently of the project (in contrary, the preprocessual callback needs to know about where to insert messages in the document)
return cregora.ajax.apply(this, Array.prototype.slice.call(arguments));
}
;
(function() {
// some scope with variables..
ajax({
url: "url",
callbackThis: this,
successCallback: function(responseText) {
console.log("I need some variables available in this scope");
},
errorCallback: function() {
console.log("I need some variables available in this scope");
}
});
})();
As I expected, you were actually overcomplicating the issue a little bit.
Instead of using the function constructor, you can build a higher order function that returns an appropriate handler and automatically wraps the function (like your preprocessors).
var callbackWrapper = function (callback) {
// Returns new anonymous function that acts as the handler
return function responseHandler (responseText) {
// Do your pre-processing
console.log(responseText);
callback.apply(this, Array.prototype.slice.call(arguments));
};
};
var ajax = function(init) {
for (var i = 0, callbacks = ["success", "error"]; i < callbacks.length; i++) {
var callbackName = callbacks[i] + "Callback";
if (init.hasOwnProperty(callbackName)) {
var callback = init[callbackName];
init[callbackName] = callbackWrapper(callback);
}
}
// This is the actual ajax function, which can operate in independent of the project (for example, the preprocessual callback needs to know about where to insert messages in the document)
return cregora.ajax.apply(this, Array.prototype.slice.call(arguments));
};
(function() {
// some scope with variables..
ajax({
url: "url",
callbackThis: this,
successCallback: function(responseText) {
console.log("I need some variables available in this scope");
},
errorCallback: function() {
console.log("I need some variables available in this scope");
}
});
})();
If you care, you can even change the callbackWrapper to use exactly the same preProcessor function every time:
var callbackWrapper = (function createCallbackWrapper () {
var preProcessor = function (responseText) {
console.log(responseText);
};
return function callbackWrapper (callback) {
// Returns new anonymous function that acts as the handler
return function responseHandler (responseText) {
var args = Array.prototype.slice.call(arguments);
preProcessor.apply(this, args);
callback.apply(this, args);
};
};
})();
Now you will have no problems at all with binding the original callback functions.
A little more explanation on the issue:
When you use fn + ".apply(...)", JS will turn the original function into a string. That is why you will have a hard time accessing closure variables, or anything else that is not in either your var closure function scope or the global scope.
It also fails in your case because after calling .bind on a function, its string representation turns into "function () { [native code] }".
That is of course not a valid function body and will give you lots of trouble.
That conversion to a string is the actual problem, and it is one that is not easily solved. For that reason, using new Function is almost never the proper solution, and once you found yourself using it, you should assume you made a mistake in your reasoning. If you didn't, and new Function is indeed the only solution, you'd know.
the problem is that when i use test.call(), it calls into my call implementation of the prototype but when i use test(), it doesnt call call(). i want to be able to use test to trigger prototype.call(). code below:
Function.prototype.call = function () {
//do something...
return this(); // call original method
}
function test() {
alert("test");
}
test.call(); //calls prototype.call()
test(); //doesnt call prototype.call()
Why would you expect test() to invoke Function.prototype.call? They're different functions.
The native .call() method that you're overwriting is not invoked every time a function is invoked. It's only invoked when you invoke it.
Invoking .call() does invoke test() because that's what it's designed to do. It expects a function as its context (this value), and invokes that function. But that doesn't mean .call() has anything to do with any other function invocation.
Here's a solution that I just whipped up (credit goes to cliffsofinsanity for pointing out a crucial error with the code and correcting it). It logs all non-standard functions called after a certain point, in the order that they were called.
// array of all called functions
var calledFunctions = [];
// custom func object that has name of function and
// and the actual function on it.
function func(_func, name) {
return function() {
calledFunctions.push(name)
return _func.apply(this, arguments);
};
}
test = function() {
alert("hi");
}
otherTest = function() {
alert("hello");
}
// put this bit somewhere after you've defined all your functions
// but *before* you've called any of them as all functions called
// after this point are logged. It logs all non-standard functions
// in the order that they are called.
for (prop in window) {
if (window.hasOwnProperty(prop) && typeof window[prop] === 'function' && window[prop].toString().indexOf('[native code]') < 0) {
window[prop] = func(window[prop], prop);
}
}
otherTest();
test();
otherTest();
console.log(calledFunctions);
Working demo can be found here.
I have a javascript function (class) that takes a function reference as one paremter.
function MyClass ( callBack ) {
if (typeof callBack !== 'function')
throw "You didn't pass me a function!"
}
For reasons I won't go in to here, I need to append something to the function by enclosing it in an anonymous function, but the only way I've been able to figure out how to do it is by adding a public function to MyClass that takes the callBack function as a parameter and returns the modified version.
function MyClass () {
this.modifyCallBack = function ( callBack ) {
var oldCallBack = callBack;
callBack = function () {
oldCallBack(); // call the original functionality
/* new code goes here */
}
return callBack;
}
}
/* elsewhere on the page, after the class is instantiated and the callback function defined */
myCallBackFunction = MyClassInstance.modifyCallBack( myCallBackFunction );
Is it possible to make this work when passing the callBack function as a parameter to the class? Attempting to modify the function in this manner when passign it as a parameter seems to only affect the instance of it in within the class, but that doesn't seem like it's a valid assumption since functions are Objects in javascript, and are hence passed by reference.
Update: as crescentfresh pointed out (and I failed to explain well), I want to modify the callBack function in-place. I'd rather not call a second function if it's possible to do all of this when the class is instantiated.
Function objects don't provide methods to modify them. Therefore, what you want to do is impossible the way you want to do it. It's the same thing Jon Skeet likes to point out about Java: Objects are not really passed by reference, but instead a pointer to them is passed by value. That means that changing the value of an argument variable to a new one won't affect the original one at all.
There are only two ways to do what you want in call-by-value languages like Java and JavaScript: The first one would be to use the (function) object's methods to modify it. As I already stated, function objects don't have those. The other one is to pass the object of which the function object is a property as a second argument and set the appropriate property to a new function which wraps the old one.
Example:
var foo = {};
foo.func = function() {};
function wrapFunc(obj) {
var oldFunc = obj.func;
obj.func = function() {
// do some stuff
oldFunc.call(obj, _some_argument__);
};
}
wrapFunc(foo);
This works for global functions as well: they are properties of the window object.
As Javascript uses lexical scoping on variables the following is possible:
var modifiableCallback=function() { alert('A'); };
function ModifyCallbackClass(callback)
{
modifiableCallback=function() { callback(); alert('B'); };
}
function body_onload()
{
var myClass=new ModifyCallbackClass(modifiableCallback);
modifiableCallback();
}
This does what you want, however the function "modifiableCallback" must be referred to with the same name inside ModifyCallbackClass, otherwise the closure will not be applied. So this may limit the usefulness of this approach for you a little.
Using eval (performance may suffer a bit) it is also possible to make this approach more flexible:
var modfiableCallback1=function() { alert('A'); };
var modfiableCallback2=function() { alert('B'); };
var modfiableCallback3=function() { alert('C'); };
function ModifyCallbackClass(callbackName)
{
var temp=eval(callbackName);
var temp2=eval(callbackName);
temp= function() { temp2(); alert('Modified'); };
eval(callbackName + " = temp;");
}
function body_onload()
{
var myClass=new ModifyCallbackClass("modfiableCallback1");
modfiableCallback1();
myClass=new ModifyCallbackClass("modfiableCallback2");
modfiableCallback2();
myClass=new ModifyCallbackClass("modfiableCallback3");
modfiableCallback3();
}
I assume you are saving this callback somewhere... Any reason this won't work?
function MyClass ( callBack ) {
var myCallBack;
if (typeof callBack !== 'function')
throw "You didn't pass me a function!"
var oldCallBack = callBack;
callBack = function () {
oldCallBack(); // call the original functionality
/* new code goes here */
}
myCallBack = callback;
}
You want to do something like:
function MyClass () {
this.modifyCallBack = function ( callBack ) {
var oldCallBack = callBack;
callBack = function () {
oldCallBack(); // call the original functionality
alert("new functionality");
}
return callBack;
}
}
/* elsewhere on the page, after the class is instantiated and the callback function defined */
var myCallBackFunction = function () {alert("original");};
var MyClassInstance = new MyClass();
myCallBackFunction = MyClassInstance.modifyCallBack( myCallBackFunction );
myCallBackFunction();