This is a common issue with JavaScript variable scoping: new variables are only introduced in a new execution context and thus, in the problematic code, i is shared across all the action callbacks.
Anyway, here is the corrected code following the standard idiom:
function getNumber()
{
  var items = [];
  for (var i = 0; i < 5; i++) {
    var num = i * 10;    
    items.push({
      id: i, number: num,
      // _i is a new variable for each callback
      action: (function (_i) {
        // use separate (one per callback) _i variable
        return function () { alert(_i) }
      })(i) // pass in current value for loop
    });
  }
  return items
}
Alternatively, if one doesn't like all the nesting, it's fine to use a "named" function to perform the same task. The key to point is that the closure is created (and returned from) a new execution context so that a different variable is closed-over:
function getNumber()
{
  function mkAction (i) {
      return function () { alert(i) }
  }
  var items = [];
  for (var i = 0; i < 5; i++) {
    var num = i * 10;    
    items.push({
      id: i, number: num,
      action: mkAction(i)
    });
  }
  return items
}
Another approach is to use Function.bind from ES5:
function getNumber()
{
  var items = [];
  for (var i = 0; i < 5; i++) {
    var num = i * 10;    
    items.push({
      id: i, number: num,
      action: (function (_i) { alert(_i) }).bind(null, i)
    });
  }
  return items
}
(Note that Function.bind can be emulated using a new execution context/closure even without native browser support. See the MDC documentation.)
See also: