Javascript中的奇怪FOR循环行为

时间:2014-02-16 14:43:32

标签: javascript loops for-loop html-table

我正在尝试生成一个包含3行和3个单元格的表 例如

<table>
<tr>
   <td> 00 </td>    <td> 01 </td>    <td> 02 </td>
</tr>
<tr>
   <td> 10 </td>    <td> 11 </td>    <td> 12 </td>
</tr>
<tr>
   <td> 20 </td>    <td> 21 </td>    <td> 22 </td>
</tr>
</table>

我正在使用的Javascript是:

tab = document.getElementById('tab');
for(i=0; i<3; i++)
{ 
 tab.innerHTML += '<tr>';

  for(j=0; j<3; j++) 
  {
   tab.innerHTML += '<td id="'+i+''+j+'">'+i+''+j+'</td>'; 
  }

 tab.innerHTML += '</tr>';
}

HTML正在:

<table id="tab">
</table>

然而,当我运行代码时,所有表元素都在第一列中结束,因此我得到的是1x9表而不是3x3表。

任何人都知道我做错了什么?

6 个答案:

答案 0 :(得分:5)

您正在将DOM视为您编写的HTML。

当你这样做时

.innerHTML += "<tr>"

..您正在创建一个完整的<tr></tr>元素。 DOM中没有“半个元素”这样的东西。


然后,当你+= <td>元素时,他们现在在你刚创建的<tr>之后,这是无效的,所以浏览器尽可能地纠正它。

// This is going after the <tr></tr>
tab.innerHTML += '<td id="'+i+''+j+'">'+i+''+j+'</td>'; 

最后,当你做

.innerHTML += "</tr>"

您只是添加了无效的HTML,因此可能会被忽略。


此外,使用.innerHTML += "...content..."非常糟糕。它首先将之前的DOM节点序列化为HTML,销毁这些DOM节点,将新HTML添加到它刚刚序列化的内容中,然后解析该HTML以创建(并重新创建)节点。

所以每次迭代,你都会破坏并重新创建你在所有迭代中创建的所有东西。这种破坏非常低效并且是不必要的。而是构建整个字符串,然后使用.insertAdjacentHTML()

tab = document.getElementById('tab');

var html = ""
for(i=0; i<3; i++)
{ 
 html += '<tr>';

  for(j=0; j<3; j++) 
  {
   html += '<td id="'+i+''+j+'">'+i+''+j+'</td>'; 
  }

 html += '</tr>';
}

tab.insertAdjacentHTML("beforeend", html);

答案 1 :(得分:5)

选项#1

您应该使用辅助字符串变量执行此任务:

var tab = document.getElementById('tab'),
    str = '';

for (var i = 0; i < 3; i++) {
    str += '<tr>';

    for (var j = 0; j < 3; j++) {
        str += '<td id="' + i + '' + j + '">' + i + '' + j + '</td>';
    }

    str += '</tr>';
}

tab.innerHTML = str;

演示:http://jsfiddle.net/hrrKg/

选项#2

我还建议使用表API

var tab = document.getElementById('tab');

for (var i = 0; i < 3; i++) {
    var row = tab.insertRow(i);
    for (var j = 0; j < 3; j++) {
        var cell = row.insertCell(j);
        cell.id = i + '' + j;
        cell.innerHTML = i + '' + j;
    }
}

演示:http://jsfiddle.net/hrrKg/1/


基本上为什么会这样。每当你设置类似的东西:

tab.innerHTML += '<tr>'

表内容变得无效HTML因此浏览器会自动修复它,使其看起来像:

<tbody><tr></tr></tbody>

进一步的循环使其更加混乱,因此产生了结果。

另外请看一下 cookie monster 的答案,因为它更全面。

答案 2 :(得分:3)

string的替代方案:

tab = document.getElementById('tab');
for(i=0; i<3; i++)
{ 
 var tr = document.createElement("tr");

  for(j=0; j<3; j++) 
  {
    var td = document.createElement("td");
    td.id = i+''+j;
    td.innerHTML= i+''+j
    tr.appendChild(td); 
  }

 tab.appendChild(tr);
}

FIDDLE

答案 3 :(得分:1)

您添加<tr>一次无效HTML的问题,并自动删除。你可以这样做:

tab = document.getElementById('tab');
for(i=0; i<3; i++)
{ 
 var html = '<tr>';

  for(j=0; j<3; j++) 
  {
   html += '<td id="'+i+''+j+'">'+i+''+j+'</td>'; 
  }

 tab.innerHTML += html + '</tr>';
}

答案 4 :(得分:1)

我做了一些小调整,让它在小提琴手中工作:

tab = document.getElementById('tab');

var result = "<tbody>";
for(i=0; i<3; i++)
{ 
 result += '<tr>';

  for(j=0; j<3; j++) 
  {
   result += '<td id="'+i+''+j+'">'+i+''+j+'</td>'; 
  }

 result += '</tr>'; 
}
result += "</tbody>";

console.log(result)
tab.innerHTML = result;

答案 5 :(得分:1)

与MamaWalter的回答一样,这是一种使用DOM节点而不是字符串连接的替代功能方法:

var tab = document.getElementById('tab');

var bind = Function.prototype.bind,
    $tr = bind.call(Document.prototype.createElement, document, "tr"),
    $td = bind.call(Document.prototype.createElement, document, "td"),
    $text = bind.call(Document.prototype.createTextNode, document),
    appender = function(parent, child) {
      parent.appendChild(child);
      return parent;
    },
    wrapWith = function(fn, child) { return appender(fn(), child); },
    wrapWithTd = wrapWith.bind(undefined, $td);

var outer = [1,2,3], inner = [1,2,3];

outer.map(function(row) {
  function createCellContents(col) {
    return $text(row+ '' + col);
  }

  return inner
    .map(createCellContents)
    .map(wrapWithTd)
    .reduce(appender, $tr());
}).reduce(appender, tab);

jsbin供参考。