According to MDN, this type of logical error in understanding JavaScript closures, is a common mistake.
There are two practical ways to solve this. Sticking with ES5 only, the most canonical way to solve this would be to use urls.forEach() instead:
var urls = ['url1', 'url2', 'url3', 'url4']
urls.forEach(function(url, i) {
console.log(urls[i]) // getting value
var opt = {
url: urls[i],
headers: {
'Authorization': 'Bearer ' + reply
}
}
request.get(opt, function(error, response, body) {
console.log(urls[i]) // getting undefined
if (!error) {
enrichment_data.push({
type: body
});
} else {
enrichment_data.push({
type: ''
})
}
})
})
Using this method, you create a new function scope that preserves the value of each i, even within the asynchronous function, so that the variable reference doesn't get overwritten by later iterations of the for loop you had earlier.
Your second option would be to introduce ES6 lexical scope variable declarations using let like so:
var urls = ['url1', 'url2', 'url3', 'url4']
for (let i = 0; i < urls.length; i++) {
console.log(urls[i]) // getting value
var opt = {
url: urls[i],
headers: {
'Authorization': 'Bearer ' + reply
}
}
request.get(opt, function(error, response, body) {
console.log(urls[i]) // getting undefined
if (!error) {
enrichment_data.push({
type: body
});
} else {
enrichment_data.push({
type: ''
})
}
})
})
Lexical scope means that any reference to i inside the block scope of the for loop, even within the body of the asynchronous function, will reference that particular iteration of the for loop, allowing it to behave as it appears like it should.
var itolet ifor lexical scope. To understand your problem, also tryconsole.log(i)in the problematic location as well.urls[i].urlis undefined