Javascript - Replace callback with function, including parameters - javascript

Though Stackexchange Meta forbids me to start with "Hi,", I think there is no substantial harm to being friendly.
Hi,
I use the following piece of code,
while (!success) {
new Magister(chosenSchool, username, password).ready(function(error){
/* Code here using the error variable above */
});
}
but JSLint warnes me that it would be a bad practice to define functions inside a loop.
However, using the following code, doesn't work either.
function checkLogin(error) {
/* Code here using the error variable above */
}
while (!success) {
new Magister(chosenSchool, username, password).ready(checkLogin(error));
}
This results into Uncaught ReferenceError: error is not defined. How can I not redefine a function, but still passing the error as in the original function(error){...}?
I tried various methods, but it won't budge for me.
Thanks in advance!

Just don't call the function:
new Magister(chosenSchool, username, password).ready(checkLogin);
ready expects a function object, so you have to pass chechLogin itself instead of calling it and passing its return value (which is likely undefined).
How can I not redefine a function, but still passing the error as in the original function(error){...} ?
Maybe that's where the confusion lies. You are actually not passing error at all. The argument is passed by the caller, which is ready.
One nice feature of JavaScript is that you can simple replace variables with the literal representation of their value (in most cases).
So if we look at
new Magister(...).ready(checkLogin(error));
and replace checkLogin with it's value (the function) it becomes
new Magister(...).ready(function checkLogin(error){...}(error));
However, that doesn't look like the first version at all! Suddenly a wild (error) appears at the end of our function definition.
Lets go the other way round:
new Magister(...).ready(function(error){...});
// becomes
new Magister(...).ready(function checkError(error){...});
// becomes
function checkError(error) { ... }
new Magister(...).ready(checkError);
Much better.

Related

Node redis doesn't like function.apply()

I'm trying to wrap a redis client in node but I seem to be having some issues with calling node-redis functions with .apply().
This is causing issues when I tried to do it, which I was able to work around, but now async is calling its functions using .apply() as well which is now causing issues.
Below is a simplification of what I'm doing:
var client = redis.createClient( myOptions );
function set(){
// do other stuff
client.set.apply( null, arguments );
}
However, when I do this I'm getting the following error:
TypeError: Cannot read property 'send_command' of null
at RedisClient.(anonymous function).RedisClient.(anonymous function) (E:\sitesroot\0\node_modules\redis\lib\commands.js:45:24)
The code works perfectly when I pass in the arguments manually like so:
function set( key, value ){
// do stuff
client.set( key, value );
}
This approach won't work though for the likes of wrapping hgetall which has an unspecified number of arguments...
Any insight on what might be causing this?
As #Bergi pointed out in the comment above, you need to pass the correct context when you apply.
client.set.apply( client, arguments );

pass argument to function, parameter doesn't become variable

Trying to learn basic javascript, but ran into some issues.
Is it true that the following script stores the string to the parameter, turning it to a variable:
function funcOne(paraOne) {
document.write(paraOne);
}
funcOne("A Message");
Am I understanding it correctly, that this is equivalent to var paraOne = "A Message"; ?
Because when I try using this variable elsewhere, an error message just shows in console saying:
ReferenceError: Can't find variable: paraOne
Wondering what I am missing here.
The scope of a parameter is limited to the function that defines it. So, for example, this would be perfectly legal:
function funcOne(paraOne) {
document.write(paraOne);
console.log(paraOne);
}
funcOne("A Message");
While this would cause a RefernceError:
function funcOne(paraOne) {
document.write(paraOne);
}
funcOne("A Message");
console.log(paraOne); // Error here!

Jasmine Unit Tests Unexpected this Reference

I am trying to test a fairly simple JavaScript function in Jasmine, however the first statement is throwing an error for being undefined.
myClass.prototype.functiontoBeTested = function() {
var x = this.method()
...
}
The above throws an error in Jasmine as method is not a function and is undefined. The prototype is altered earlier to have this method, and out of curiosity I assigned this method to my test object in the spec itself as such:
myObject.method = function(){return mockResults;};
So I decided to log this to the console and instead of it being my object, I see Window {top: Window, location: Location, document: document, window: Window, external: Object…} which doesn't seem right. I've had this issue before with testing a function in Jasmine that used this but just changed the source code to refer to the object by name since the function was being assigned to something within the closure. I can't do that in this case, and I'm curious why this is referring to something unexpected (at least to me).
Edit: Some details on what the test case looks like as requested:
it("updates the control count", function(){
var mockResults = { ... };
myObject.method = function() {return mockResults;};
expect(myObject.method).not.toThrow();
});
Right now I'm just trying to get the method to execute to completion during the test. The function to be tested updates the text on some HTML components, I'll work on verifying those once I can get it to actually run. The method that is causing an error is the first line of the function, and is simply an accessor method for the object being called. In actual execution, var x = this.method() runs without issue. When testing in jasmine var x = this.method() throws an error because method() is undefined for this. Instead of this referring to the calling object, it is referring to the window. This doesn't happen live, but only during testing with Jasmine. This method is undefined even when I forcibly define it for the test object just prior to execution in the test as above. That's when I decided to log this to console in the source code and realized it isn't referring to what I would have expected it to refer to.
In JavaScript this for a method depends on the context it was called from. When you do a call myObject.method(), then method was called from the context of myObject, therefore this is myObject.
When you pass your function to Jasmine toThrow matcher, it calls it as it was passed (see source code):
try {
actual();
} catch (e) {
// ....
}
Here, actual() is a call of your method. It has no any specific context, so by default it will be called from window context.
Solution is to explicitly bind you method to myObject like the following:
expect(myObject.method.bind(myObject)).not.toThrow();
Credits to questions, you can find more details there:
Does Jasmine's toThrow matcher require the argument to be wrapped in an anonymous function?
How to write a test which expects an Error to be thrown in Jasmine?

Javascript structured error handling

I am developing my first Javascript app and I am trying to go object oriented.
There is a basic closure that returns my primary object and every function I invoke rests in that object. Some pseudo code would look like this:
primary = (function(){
var object = {
doSomething = function(){};
},
return {intance:function(return object)}
});
//invocation
primary.instance().doSomething();
What I am trying to achieve is to attach an error handler function to my object, so that whenever there is an internal error, it is cought, and I don't have to wrap every function call in a try catch block.
I tried object.onerrorbut the error went on to window object. Maybe I am getting the concept wrong. I tried searching on Github for some simpler framework that includes structured error handling, but no luck. I am pretty familiar with this in PHP, but I haven't done this so far in Javascript. Can somebody show me an example how it is done right?
EDIT: I know that structured error handling goes further, I am just trying to get a root handler, so that no errors / exceptions can pass on to the window object
Dealing with the error event without a try catch block will halt the execution of your script (except for any asynchronous functions that have already been called).
You can suppress (non-ajax, non-syntax) errors by capturing them on document.body or a more specific object, and stop them being thrown to the user (or reaching the window object) by using e.preventDefault() or return false, and send them to a global/object handler (to inspect or log) by passing the event object as an argument - but any of those options will stop your script execution beyond the point of error. That's the main benefit of a try catch block, and as far as I know there is no way around that.

A weird prototype loading thing with Yabble.js

I have a very odd problem that I have to assume is because of Yabble.js. I have never used Yabble.js before, and the only reason I am now is because it is a dependency of a library I'm using (Gamejs), but I would love to understand why this happens, and whether it is actually Yabble.js's fault, or possibly Gamejs's.
Here's a heavily compressed (and modified for genericness) version of my main.js:
var gamejs = require('gamejs');
...
function Character(/*lots of arguments*/) {
Character.superConstructor.apply(this, arguments);
this.somethingtomakeitaprototypeforthisexample = oneofthearguments;
}
gamejs.utils.objects.extend(Character, gamejs.sprite.Sprite);
Character.prototype.draw = function(display){
display.blit(this.animator.image, this.pos);
}
... /*Skipping most of the file, irrelevant to the problem*/
function main() {
maincharacter = new Character(/* appropriate number and types of arguments */);
... /*skipping the rest*/
}
gamejs.ready(main);
I have done enough debugging to know that it gets into the main function no problem and that the break occurs at the call to Character. Here is the error message (from Chrome's console):
Uncaught TypeError: undefined is not a function
main
_readyResources
I have determined that Character is the undefined function. However, if I define my ready function thusly:
gamejs.ready(function(){
console.log('Character:');
console.log(Character);
main();
});
the full contents of Character, as properly defined, prints out, but I still get the error in main. Thus, I know that Character is defined by the namespace before main is called.
Fun fact though: I do have a workaround. If I change the function prototype for main to:
function main(CharacterClass) {...};
then change the ready function to:
gamejs.ready(function(){ main(Character); });
and change the relevant line in main to:
var character = new CharacterClass(...);
it works fine. But this feels really hackish.
So my question is not how to make it work, since I have that already, but rather why it is a problem and how to make it work like it's supposed to.
Any thoughts?

Categories

Resources