Попробую описать словами.
В Вашем случае, на момент вызова a[3](), переменная i имеет последнее значение из цикла.
Соответственно, я применил IIFE, чтобы сохранить значение i, создав новый контекст.
'use strict';
var a = [1,2,3,77,5,6];
var b = [];
for (var i in a) {
b.push(a[i]);
a[i] = (function(i) {
return function() {
return b[i];
};
})(i);
}
console.log(a[3]());