You are mixing up concepts. Leaving closures out of this (it is something else entirely), let's look at the question you asked.
why in the following code the array dogs is not filled two the same
objects {name: 'lunski', species: 'dog'}
You are pushing two distinct objects (animals[0]
and animals[2)
) into the dogs
array - they are not references to the animals
object itself (arrays are objects) but to the objects contained in the individual animals
elements.
Because this is not a closure The variable i
is not fixed to the last value it is set to.
UPDATE
I believe I finally understand your intended question - here is an answer showing how an anonymous function with closure and an anonymous function without closure works with your array (see this fiddle to test).
The code / fiddle creates 4 inputs. The first and third are without closure and the second and fourth are with closure. The inputs are meant to be clicked on (they have a click
listener) and they each log animals[i]
to the console. See the comments in the example below to explain the values logged.
var animals = [
{name: 'fluffy', species: 'dog'},
{name: 'miauw', species: 'cat'},
{name: 'lunski', species: 'dog'}
];
var dogs = [];
for (var i = 0; i < animals.length; i++) {
if (animals[i].species === 'dog') {
// the first and third elements created in the loop have no closure
// the variable i will be set to 2 because it has reached the end of its loop - it's value was not bound with function
// therefore when you click on the input labeled "fluffy (no closure)" or lunski (no closure) they will log "undefined" to the console since animals[2] is undefined.
e = document.createElement("input");
e.value = animals[i].name + " (no closure)" ;
e.addEventListener('click', function() {
console.log(animals[i])}
)
document.body.appendChild(e);
// the second and fourth elements created in the loop have closure
// because the function is enclosed within a function
// the variable i will be valid and set to what it is when the funtion runs
// Note: The exclamation point causes the outer function to be executed immediately - creating the event listener
// therefore when you click on the input labeled "fluffy (closure)" or lunski (closure)
// you will see the whole object in the console
e = document.createElement("input");
e.value = animals[i].name + " (with closure)" ;;
!function(animals, i){
e.addEventListener('click', function() {
console.log(animals[i])}
)
}(animals, i)
document.body.appendChild(e);
}
};
I hope this helps. If you are interested in seeing more examples of closures, look at this SO post