Транзакция выполняется асинхронно, поэтому вам нужно что-то сделать с результатом обратного вызова. Например:
..
tx.executeSql('SELECT id, title, weight, reps FROM exercises', [],function(tx, rs) {
var result = [];
for(var i=0; i<rs.rows.length; i++) {
var row = rs.rows.item(i)
result[i] = {
id: row['id'],
title: row['title'],
weight: row['weight'],
reps: row['reps']
}
}
console.log(result);
});
..
Запишет результат на вашу консоль.
В коде, который вы разместили в своем вопросе, ни один из обратных вызовов не выполняется до того, как выполнение достигнет оператора return result
- т.е. массив еще не был бы заполнен - потому что executeSql асинхронный: он не блокируется во время выполнения и просто выполняет обратный вызов с ошибкой или успешным завершением.