I am trying to call a nested function which is stubbed.
I am using sinon for stubbing.
function logger(){
function log(msg){
sendMsg(msg)
}
var sendMsg = function (msg){
console.log("original func")
}
return {
log:log,
sendMsg:sendMsg
}
}
I am stubbing the 'sendMsg' func and trying to call it from log function, but instead of the stubed function, the original one is called.
The weirdest thing is that when I call sendMsg with this.sendMsg it calls the stub.
Im sure there is a JS principle im not aware of, Ill be glad you can point me to one..
Thanks
The log() function refers directly to the symbol sendMsg to call the function. The only sendMsg visible to log() is that local variable to which the the "real" function is assigned. Changing the value of the "sendMsg" property on that returned object cannot affect that; log() will always call the "real" sendMsg() function.
If log() were written to call this.sendMsg instead, then your stub function would be called.
Related
So basically why do I have to use this kind of method in these kind of situations in particular?
function Example(callback) {
// What's the purpose of both 'call()' and 'null'?
callback.call(null, "Hello")
}
Exemple(function(callback) {
alert();
})
I've figured it out this syntax in a open project code but I haven't found out why it works yet.
You don't need to use call() in this situation. call() is used when you need to set the value of this in a function. If you aren't doing that, just call the function like you would any other function. For example:
function Example(callback) {
// call the function passed in
callback("Hello")
// this also works, but there's no benefit here
// because the callback doesn't care about `this`
// callback.call(null, "Hello")
}
// pass a callback function to Example
Example(function(text) {
console.log(text);
})
You would use call in situations where the callback function needs a value for this. For example:
function Example(callback) {
let person = {name: "Mark"}
// set this in the callback to the person object
// and the execute it with the argument "Howdy"
callback.call(person, "Howdy")
}
Example(function(greeting) {
// the callback function depends on having this.name defined
console.log(greeting, this.name);
})
This looks pointless at the first glance, however, there might be valid reasons for this syntax, for example:
the callback relies explicitly on this being null and not some global default
the callback is not necessarily a function, it can be a "function-alike" object that provides a .call method
callback.call(... is used consistently through the application, no matter if this is needed or not
in Node.js I have this code:
console.log('starting');
function sayHello() {
console.log('HEllo!!');
}
setTimeout(() => {
console.log('inside of callback');
}, 1000);
console.log('finishing app');
Why if I run through the terminal the (App) file it displays the result of the setTimeout function but not the sayHello? After all, I did not call the setTimeout function either!
Moreover, if then I store the setTimeout function in a variable like
var x = setTimeout(() => {
console.log('inside of callback');
}, 1000);
the function is called automatically as well! Why?
There is no link with function or method here. It's about declaration and call.
When you do :
function sayHello() {
console.log('HEllo!!');
}
You declare a function sayHello that won't be called. To call it, you need to do sayHello(); after declare it.
When you use setTimeout(), you are calling a built-in function already declared for you by JavaScript. To know how to use the function that is already declared, you need to check a documentation of the function. Example : check here (part syntax).
Note : Every function in JavaScript is attached to an object, so every function is a method. setTimeout, for example, is attached to the global object (in browser, it's window, in Node it's global). Your sayHello() function will be also attached to her scope.
The implementation of setTimeout is something like (this is only a mock implementation):
function setTimeout(callback, interval, ....args) {
// wait for `interval` time to pass
callback(...args);
}
As you can see, setTimeout is a function which takes a function(callback in the above example) as a parameter, and calls that function after interval time has passed.
If I call the function once like this
var button = document.querySelector('button');
button.addEventListener('click', once);
function once() {
console.log('one');
button.removeEventListener('click', once);
}
It's calling only once.
But if I called like this once()
var button = document.querySelector('button');
button.addEventListener('click', once());
function once() {
console.log('one');
button.removeEventListener('click', once());
}
Exception throws
Exception: InternalError: too much recursion
Could you please explain why this is happening.
() after function name invoke's the function. So as button.addEventListener('click', once()); you are bind the return value of once() method which is undefined.
And since once() is called recursively without any break statement, you are getting the InternalError: too much recursion.
You should pass the function reference.
button.addEventListener('click', once);
For Additional Info:
Pointer Vs Delegates
If you put () after the name of a variable holding a function, then you call the function.
If a function calls itself, then it will get called, call itself, call itself again and so on unto infinity. This is recursion. Doing something unto infinity will cause a computer to run out of memory, so it is undesirable.
JavaScript engines prevent this by throwing an exception when you try it.
(There are exceptions, of course, a function that calls itself conditionally can be very useful).
The first code is correct, because you register the function to be called.
The second code tries to register the result of the function call once(). This means you actually execute the function when you only want to register it. Now, in your function body, you do the same to deregister the callback. Here again, you call the function you are already executing and hence, you recurse infinitely.
I have the following jQuery code:
function next() {
//some code here
}
function previous() {
//some code here
}
$("#next").click(function(){
next();
});
$("#previous").click(function(){
previous();
});
This works, but this doesn't:
$("#next").click(next());
$("#previous").click(previous());
Why is this happening? Is there a problem in my code, or is this just a thing with jQuery? Note: #next and #previous refer to two buttons in my html file.
The callback should be a reference to the function.
Why $("#next").click(next()); doesn't work?
func() is a function call and not a reference, which is why it is called immediately.
This,
$("#next").click(function(){
next();
});
is a preferable way in case you need to pass arguments.
Else,
$("#next").click(next) //notice just the signature without ()
This works (if the functions next and previous are defined):
$("#next").click(next);
$("#previous").click(previous);
In this case the next and previous are also callback functions, the difference between the two is,
when you call this line
$("#next").click(next()); the function is executed immediately, and you are passing the result of the next function to the eventHandler of jQuery.
and in this case
$("#next").click(next); you are passing the function next to the EventHandler of jQuery.
Btw.: in the jQuery API Documentation (https://api.jquery.com/click/) it shows all parameters for the click function and the required types it states: "...handler Type: Function( Event eventObject ) A function to execute each time the event is triggered. ..."
try like this you will get your answer,
function next() {
//some code here
}
function previous() {
//some code here
}
$("#next").click(next);
$("#previous").click(previous);
working demo jsfiddle Example
What is going on there is a little bit obscured by the syntax of anonymous functions function() { ... }. What you are doing by that is passing a function, without calling it. And I want to explain how this works:
If you have a simple function
function next() { return 5 };
It will simply return the value 5, if you call it from somewhere:
a = next(); // value of a will be 5
But what you can do too, is to pass the whole function to a. This is possible, because functions in JavaScript are actually objects:
a = next;
b = a(); // value of b will be 5
If you look at the syntax, it shows you, that putting parentheses () at the end of a function invokes it, and returns the return value. While the naked string, without parentheses hands you the function itself.
So what is a callback now, and what does click() like to get as a parameter? A callback function is a function, that gets called later; we actually hand it over, to get called later. click() would like to get such a function as parameter, and it should be clear now, that we have to pass the function without parentheses, to enable click() to call it later, instead of just passing a 5 to it.
$("#next").click(next);
So how does then the initial syntax with the anonymous function work?
function() { next(); }
actually wraps your next() into another function, which is anonymous – because it does not have a name – but is working in the same way as a named function. You can even set a variable by it:
a = function() { next(); } // a will be the anonymous function that calls next()
But calling that function a() will return nothing, because the anonymous function does not return a value (To be exactly: every function call in JavaScript is returning at least undefined, but that's a technical detail).
It can even be called immediately by putting parenthesis at the end of it:
a = function() { return next(); }() // value of a will be 5
Adding the return there will make sure, the return value of next() will be passed through the anonymous function.
This should make clear why
$("#next").click(function(){ next(); });
is working, and why
$("#next").click(next());
is not, but
$("#next").click(next);
will be a good solution.
$("#next").click(next); would work. Notice parenthesis are not required as the function/callback handler should be passed as a parameter.
I have a javascript function that has a callback then an anonymous function then another callback, and something has gone wrong with the scope. The parameter callbackFunc is retaining its value from the first function call and not using the new value passed in the 2nd function call.
function IsReady(callbackFunc) {
if (!IsValid()) return false;
IsConnected(function () {
if (typeof (callbackFunc) == 'function')
callbackFunc();
return true;
});
}
function IsConnected(validCallbackFunc) {
$.post("IsConnected", function (data) {
if (data.IsValid) {
if (validCallbackFunc && typeof (validCallbackFunc) == 'function')
validCallbackFunc();
}
});
}
$('#SaveButton').click(function () {
IsReady(SaveInvoice); // works
});
$('#ExportButton').click(function () {
// works only if IsConnected() is true
// otherwise SaveInvoice is called again
IsReady(ExportInvoice);
});
function SaveInvoice() {}
function ExportInvoice() {}
In some circumstances, when I click the ExportButton, the SaveInvoice function is run instead of the ExportInvoice function. I'm guessing that it's a scoping issue - that somehow the old value of callbackFunc has been retained. But I don't quite understand it due to the mix of callback + anonymous function + another callback. I didn't write this code, but I have to fix it. Is there anything I can do to clear the value of callbackFunc at the end of IsReady()?
IsReady(ExportInvoice) works if IsConnected() is true. If IsConnected() is false then the result is that SaveInvoice() gets executed when in fact nothing should happen (because it is not connected).
There is no way that the callbackFunc value could be retained between two different calls of the IsReady function.
In your code, each time a click event handler is executed, a new scope is created when IsReady is called. Each scope has it's own local parameter callbackFunc. Each scope will define its own anonymous function passed to IsConnected where resides the callbackFunc variable enclosed in a closure.
So this is not a scope problem.
To prove it, I emulated your code here: http://jsfiddle.net/pwJC7/
In your code you talk about the IsConnected return value. This function actually does not return anything. The connection status seems to be checked through an ajax call returning an XML or JSON data with an IsValid property (emulated by $_post in the fiddle).
Maybe your issue is due to this asynchronous call. But it's impossible that you experience a call to SaveInvoice function as a consequence of a click to ExportInvoice button with the JavaScript code you provided.