String stored inside an array becomes undefined in JavaScript

2

I have some text strings stored in an array and I want to use them to add a CSS property to a series of images.

var img = document.getElementsByClassName("post-image");
var link, w, h;
var margenes = [];

for (var i = 0; i < img.length; i++) {

    // Obtener la url de las imágenes externas al DOM
    link = img[i].parentElement.href;

    // Insertar una <img src="link"> en el DOM
    document.getElementById("thread").insertAdjacentHTML("afterbegin", "<div id='lightbox'><img id='lightbox-img' src='" + link + "'></div>");

    // Utilizar las variables h, w para almacenar el alto y ancho de la imagen
    var lightboxImg = document.getElementById("lightbox-img");
    w = lightboxImg.width;
    h = lightboxImg.height;

    // Construir una cadena de texto con los valores de h y w para mandarla al arreglo
    margenes.push("-" + Math.floor(h / 2) + "px 0px 0px -" + Math.floor(w / 2) + "px");

    // Eliminar la imagen del DOM
    document.getElementById("lightbox").parentNode.removeChild(document.getElementById("lightbox"));

}

for (var i = 0; i < img.length; i++) {
    // Comprobar que imprime la cadena de manera adecuada
    console.log("Prueba " + margenes[i]);
}

for (var i = 0; i < img.length; i++) {

    // Cuando el puntero está sobre una de las imágenes
    // no son las mismas que el ciclo for anterior
    img[i].addEventListener("mouseover", function () {
        link = this.parentElement.href;
        document.getElementById("thread").insertAdjacentHTML("afterbegin", "<div id='lightbox'><img id='lightbox-img' src='" + link + "'></div>");
        var lightboxImg = document.getElementById("lightbox-img");

        // No funciona
        lightboxImg.style.margin = margenes[i];

        // Imprime "Valor: undefined"
        console.log("Valor: " + margenes[i]);
    }, false);

    img[i].addEventListener("mouseout", function () {
        document.getElementById("lightbox").parentNode.removeChild(document.getElementById("lightbox"));
    }, false);

}

My question is why in the third cycle for that string appears as undefined ?

I have tried the following, but it is not a solution to the problem either:

String(margenes[i]);
    
asked by akko 18.05.2017 в 04:05
source

1 answer

5

There is something that you should take into account of JavaScript and it is something that confuses a lot when you come from another language, analyze the following snippet and then observe the result in the console:

for (var i = 0; i < 10; i++) {

  setTimeout(function () {
  
    console.log(i);
  
  }, 100);

}

The logic would say that the previous code should launch in console the values that i has taken over the course of the cycle but it is not, at the moment when the setTimeout is launched, i is 10 (the last value it took before the cycle ended) and this occurs because the scope of a variable in JavaScript is limited to the function in which it was declared instead of the block of code in which it has been declared. You will understand why you get an error: you are trying to access an index that is not within your Array , because this index has as value the last one that took the variable increment of the cycle for .

To prevent this from happening, we usually use a IIFE :

for (var i = 0; i < 10; i++) {

  (function(i) {
  
    setTimeout(function () {
    
      console.log(i);
    
    }, 100);

  })(i);

}

Or to understand it in a more readable way, you can create a separate function:

function lanzar(i) {

  setTimeout(function() {

    console.log(i);

  }, 100);

}

for (var i = 0; i < 10; i++) {

  lanzar(i);

}

This has been fixed in ECMAScript 2015 with the use of let . Since the scope of a variable declared with let (or const ) it is circumscribed to the block of code in which it has been declared:

for (let i = 0; i < 10; i++) {

  setTimeout(function() {

    console.log(i);

  }, 100);

}

You can use the method that you consider best. Your code must follow one of these techniques to make it work. In the following snippet I give you an example using a IIFE :

var margenes = ["cero", "uno", "dos", "tres", "cuatro", "cinco", "seis", "siete", "ocho", "nueve"];
var len = margenes.length;

for (var i = 0; i < len; i++) {

  (function(i) {

    var div = document.querySelector("div[data-index='" + i + "']");

    div.addEventListener("click", function() {

      console.log(margenes[i]);

    });

  })(i);

}
.box {
  background-color: #CCC;
  border: 1px solid #FFF;
  color: #FFF;
  cursor: pointer;
  float: left;
  font-family: Arial;
  font-size: 12px;
  font-weight: bold;
  height: 50px;
  line-height: 50px;
  text-align: center;
  width: 50px;
}
<div class="box" data-index="0">0</div>
<div class="box" data-index="1">1</div>
<div class="box" data-index="2">2</div>
<div class="box" data-index="3">3</div>
<div class="box" data-index="4">4</div>
<div class="box" data-index="5">5</div>
<div class="box" data-index="6">6</div>
<div class="box" data-index="7">7</div>
<div class="box" data-index="8">8</div>
<div class="box" data-index="9">9</div>
    
answered by 18.05.2017 в 09:18