Scope: this, that and window
this. Unfortunately, what
this refers to differs depending on what called the function containing
this. A common example, shown below, is what happens when
setTimeout is called.
In the example below a Dog object is created, with a bark function. The Dog ralph is instantiated with the name ‘Ralph’ and when
ralph.bark() is called, “Ralph” is printed to the console.
What becomes confusing is what happens when
setTimeout is called with the parameters
ralph.bark and 500. After 500 milliseconds
ralph.bark is called, however, nothing is printed to the console.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Mozilla Developer Network refers to the problem above as ‘The ”
this” problem’. What happens is
bark() refers to the browser’s
window variable when
bark() is called from setTimeout.
1 2 3 4 5 6 7 8 9 10 11
In each of the above the bind, or proxy functions explicity ensure that
ralph.bark refers to ralph and not
window. In the final example an anonymous function is called and provides another way of fixing the
Callbacks in Loops
When I launched Understoodit.com in May I included a waitlist for interested users to signup. I was planning on inviting a few dozen users a day, however, due to a deluge of emails sending out invites was delayed by a week or two.
To send the invites out, I went to Understoodit’s admin panel and seleted 40 people on the waiting list and clicked invite. A few days later I noticed that only a few individuals had accepted the invite. I looked at Postmark’s logs and noticed that invites were only sent to 5 individuals. What’s more those 5 individuals had received anywhere from 5 - 15 emails each. Meanwhile, the other 35 invitees had received no emails. The bug: I had a callback in a loop that iterated over all the selected invities and 1) called databaseModule.addInvitedUser, which created an invite token and added that invite to the database and 2) sent an email with the newly created token. Below is a simplification of the code, with error handling removed.
1 2 3 4 5 6 7 8 9 10
What went wrong was that the anonymous function “captures the variable i, not its value”. The value of
i is dependent on when the anonymous function is called, which varries depending on how long it takes to add the invited user to the database.
The solution I used was to wrap the anonymous function with an immediately invoked function expression (IIFE). The IIFE “locks” in the value of
i ensuring that
emailModule.sendInvite() refers to a different value of i on each IIFE call. Alternatively, one could create a second function outside of the loop and then call that (see option 2), a solution that would likely be easier to read.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
The problems with global variables have been discussed many times before. Suffice it to say that you should avoid them by using
var x = 0; vs x = 0;) when first declearing a variable. If you have a variable that has unaccounted for properties or values, there’s a chance that a global variable could be to blame.
I’d highly recommend defining all your variables at the top of the function to make it as clear as possible when a var is missing. Furthermore I’d recommend using JSHint which can warn you of global variables.
Values in HTML forms
1 2 3 4 5
When it comes time to get the form’s values, and use them within an application, I usually do something like:
1 2 3 4 5
Unfortunately the value that jQuery returns is a
String, and comparing it to 1, a
Number returns false. Here are several solutions to this:
1 2 3 4 5 6 7 8 9 10
In the first two examples orderSize is explicitly converted to a
Number using the
Number constructor and the global
parseInt function. In the third example the double equals coerces orderSize to a
Number before comparing to 1 (MDN on comparison operators). However, I’d recommend going with the last approach, which allows you to use orderSize as a
Number in multiple spots without having to repeatedly caste to a number. If you don’t like the last approach I’d recommend the first or second approach, since it seems to be generally preferred to use the strict equal (tripple equal signs) and not to use the double equal sign.