0

I'm trying to implement jquery hotkeys in a for loop.

acKey = [
    ["keydown", "alt+d", open],
    ["keydown", "alt+a", close],
    ["keydown", "alt+s", max],
];
for(i=0;i<=acKey.length;i++)
{
    $(document).bind(acKey[i][0], acKey[i][1], acKey[i][2]);
}

However, it turned out error Uncaught TypeError: Cannot read property '0' of undefined. What's wrong with my code?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Lewis
  • 14,132
  • 12
  • 66
  • 87
  • 4
    Your loop is `for(i=0;i<=acKey.length;i++)` (note the `i<=acKey.length`). What happens when `i==acKey.length`. Does `acKey[3]` exist? – Matt Mar 11 '14 at 09:29
  • So what should I do in this case? – Lewis Mar 11 '14 at 09:30
  • 1
    Remove the `=`; it should be just `i – Matt Mar 11 '14 at 09:30
  • 2
    Sometimes you do need "<=" in a for loop, but it's very much the exception. Any time you do use "<=", think about adding a comment to say why. – slim Mar 11 '14 at 09:31

2 Answers2

4

With due credit to @Matt who's comment points it out.

The commonest format for looping through an array is:

 for(var i=0; i<array.length; i++) {
     doSomethingWith(array[i];
 }

Note that's a "less than" operator, not a "less than or equal to" operator.

This loop counts from 0 to array.length - 1, because the second part of the for statement: i < array.length, means "keep repeating for as long as i is less than array.length.

... and that's what you want, because arrays are numbered from 0 to length-1. That is, an array of length 4 is numbered 0,1,2,3.

If you loop while i <= 4, then the loop will execute for 0,1,2,3,4 -- and in Javascript, it will get undefined when it references array[4].

Sometimes you do need "<=" in a for loop, but it's very much the exception. Any time you do use "<=", think about adding a comment to say why.

slim
  • 40,215
  • 13
  • 94
  • 127
1

Your problem is your index (out of bounds) when i=acKey.length.

You can use i<acKey.lenght or implement a "for each" iteration to avoid confusion:

acKey = [
    ["keydown", "alt+d", open],
    ["keydown", "alt+a", close],
    ["keydown", "alt+s", max],
];

var sub;
for(i in acKey) {
    sub = acKey[i];
    $(document).bind(sub[0], sub[1], sub[2]);
}
cardeol
  • 2,218
  • 17
  • 25
  • That's quite new to me. Thank you, cardeol. – Lewis Mar 11 '14 at 09:45
  • `in` shouldn't be used to loop over arrays generally. See explanation here: http://stackoverflow.com/a/3010848/355499 – Emil L Mar 11 '14 at 09:46
  • In this case is completely safe. – cardeol Mar 11 '14 at 09:49
  • Could you guys all point out this in several lines? Which cases are not safe? – Lewis Mar 11 '14 at 09:52
  • I.E. If you use an object inherited properties are also enumerated. but in case of arrays shouldn't be any problem. I use a lot this structure. Even with objects. http://stackoverflow.com/questions/11846484/each-for-object – cardeol Mar 11 '14 at 09:55
  • Your method is really useful. Thanks for explanation, cardeol. – Lewis Mar 11 '14 at 10:01
  • @cardeol It's safe as long as no one adds properties to Array (which I'd consider a big no no, but still). Consider: `Array.prototype.Muahahaha = "Gee will this show up everywhere I use 'in' to loop over an array? You bet ya!"; a = [1,2]; for(i in a) { console.log("i:" + i + ":" + a[i]);`. A bit contrived I know, but with javascript you just can't be sure :) – Emil L Mar 11 '14 at 19:42