如何遍历对象数组并在mouseover函数中填充对象?

时间:2019-05-23 14:48:55

标签: javascript

我是一年级的学生,我一直在浏览Stack Overflow,并且已经阅读了很多有关对象问题(参考)的信息,但是我不知道解决问题的方法。

我制作了对象数组,并遍历它们,以divimgname之类的所有信息填充value,到目前为止,在这里没有问题。

问题在于用当前循环通过的对象填充mouseover函数(附加到图像),因此稍后当我将鼠标悬停在图像上时,该特定对象的所有信息都会显示在另一个{{ 1}}。

div

在函数for (i = 0; i < arrgezelschap.lenght; i++) { var x = arrgezelschap[i]; var element = document.createElement("img"); element.src = x.artikelFoto + "k.jpg"; element.addEventListener('mouseover', function() { showinfo(x) }); inhoud.append(element); } 中,输出始终是数组的最后一个对象。

这是为什么,我需要怎么做才能将其保存或指向当前在函数中循环通过的对象?

5 个答案:

答案 0 :(得分:2)

TL; DR:将var x更改为let x

我真的无法比Creating closures in loops: A common mistake做得更好,但是我会尝试重新措辞。

比较这两个摘要的输出(如下)。唯一的区别是varlet。该示例演示了如何循环创建5个函数,但尚未调用它们。每个函数都引用在循环内,循环外和for内声明的变量。然后,在循环结束时,我们调用所有函数以查看得到的结果。

在第一种情况下,变量outsidei(循环变量)和inside(在循环内部声明)都用var声明。在循环的每次迭代中,它们都是相同的变量。内部var提升到示波器的顶部(循环外部)。

调用我们创建的所有函数时,我们将看到它们都引用每个变量的唯一实例,并且它们都具有循环完成后变量具有的值。

let functions = [];
var outside = 0;
for (var i = 0; i < 5; ++i) {
  outside = i * 10;
  var inside = i * 100;
  functions.push(() => { console.log(outside, i, inside); })
}
functions.map(f => f()); // call all the functions

输出:

40 5 400
40 5 400
40 5 400
40 5 400
40 5 400

在第二个示例中,所有变量都用let声明。 i中声明的变量for和循环体内声明的变量inside在循环的每次迭代中都是不同变量。但是outside变量是在循环外部声明的,因此在循环的每次迭代中仍然只使用一个outside变量。

当我们调用这次创建的所有函数时,我们看到每个函数都显示一个不同的变量iinside,它们的值是它们在循环的特定迭代过程中所持有的值,因为变量仅在该循环的迭代中存在,并且函数已绑定到该迭代所使用的变量的实例。但是outside变量在每次迭代时都是相同的变量,并且仅包含一个值:它在循环结束时具有的值。

let functions = [];
let outside = 0;
for (let i = 0; i < 5; ++i) {
  outside = i * 10;
  let inside = i * 100;
  functions.push(() => { console.log(outside, i, inside); })
}
functions.map(f => f()); // call all the functions

输出:

40 0 0
40 1 100
40 2 200
40 3 300
40 4 400

在您的情况下,每个函数都绑定到同一(唯一)变量x。如果将x的声明从var x更改为let x,那么对于每次循环迭代,您将获得一个不同的变量x,并且事件监听器函数将被绑定每次都更改为不同的x,该值将具有对应于该循环迭代的值。


脚注:希望functions.map(f => f());不会让您感到困惑。它只是调用数组中的所有函数。与此相同:

for (var index = 0; index < functions.length; ++index) {
    functions[index]();
}

答案 1 :(得分:1)

这是因为x是此处的引用,而不是值,并且在循环时会更改。看看这个:

let x = 0;
let fcn = a => console.log(a);

function execAnotherFcn(fcn) {
  fcn(x);
}

execAnotherFcn(fcn);
x++;
execAnotherFcn(fcn);

答案 2 :(得分:0)

@PopHips答案解释了出问题的理论。因此,这是您的代码的一个有效示例,因此您可以遵循它。

for(i =0;i<arrgezelschap.lenght;i++){ 
   var x = arrgezelschap[i];
       var element = document.createElement("img");
       element.src = x.artikelFoto + "k.jpg";
       element.dataset.identifyer = i;
       element.addEventListener('mouseover', function(e) { 
           showinfo(arrgezelschap[e.target.dataset.identifyer]) 
       });
       inhoud.append(element);
}

因此,因为我们使用的是事件列表器,它将提供EventArgs对象,该对象包含一个称为target的属性,该属性是受影响的HTMLElement。我们可以使用数据集(data-)系统将标识符保存到对象的数据集中,以便在事件处理程序中使用它。

请注意,不应按原样使用此答案,此答案有一些非常不好的做法,永远不要在生产代码中创建函数

答案 3 :(得分:0)

您可以使用dataset属性来存储您的信息。

这是我的实现方式

const root = document.querySelector('#root');

function createImagePlaceholder(color, data) {
  const el = document.createElement('div');
  el.style.width = '50px';
  el.style.height = '50px';
  el.style.margin = '5px';
  el.style.backgroundColor = color;
  el.dataset = data;
  
  root.appendChild(el);
  
  
  el.addEventListener('mouseover', () => {
    document.querySelector('pre').innerText = JSON.stringify(data);
  });
  
  el.addEventListener('mouseleave', () => {
    document.querySelector('pre').innerText = '';
  });
}

createImagePlaceholder('red', { text: 'I am a red block' });
createImagePlaceholder('blue', { text: 'I am a blue block' });
<div id="root"></div>
<pre><pre>

答案 4 :(得分:0)

您可以通过确定元素块级别的范围来解决此问题。 发生这种情况是因为x的值是作为闭包发送的,而var则定义为函数级别。事件列表器函数将在以后的时间执行(而不是在主线程中执行),因此x的值为循环更改为最后一个值。 可以使用let关键字或IIFE来完成。

1。

    for (i = 0; i < arrgezelschap.length; i++) {
      let x = arrgezelschap[i];
      let element = document.createElement("img");
      element.src = x.artikelFoto + "k.jpg";
      element.addEventListener('mouseover', function() {
        showinfo(x)
      });
      inhoud.append(element);

}

2。

for (i = 0; i < arrgezelschap.lenght; i++) {
  var x = arrgezelschap[i];
  var element = document.createElement("img");
  element.src = x.artikelFoto + "k.jpg";
   (function(x){element.addEventListener('mouseover', function() {
    showinfo(x)
  });})(x);
  inhoud.append(element);
}