You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Array.from转nodeList时报Cannot read 'style' of undefined错误

错误定位

  • 你怀疑自己拿到的对象不是NodeList的判断是对的:用来转换的bottles变量是document.getElementById("bottles")获取到的单个<ul>DOM节点,本身就不是可迭代的元素集合(NodeList/HTMLCollection)。
  • 触发报错的直接原因:调用Array.from(bottles)时传入的是这个单个ul节点,不是存放li的集合。Array.from()作用在单个DOM节点上时,只会遍历这个节点本身的可枚举属性,根本不会返回它内部嵌套的li元素列表,转换后的数组和你创建的li完全对不上,用bottlesArray[j]取到的自然是undefined,读取undefined的style属性就会触发报错。
  • 你用扩展运算符[...bottles]转换失败的原因和上面完全一致:单个DOM节点不是可迭代的元素集合,自然无法拆出你想要的li列表。
  • 额外的逻辑冗余问题:你在每追加一个li的循环里,都重复执行一次全量数组转换,哪怕转的是正确的集合,这种写法也完全没必要——你手头本来就保存了刚创建好的liElement引用,根本不需要之后再从DOM里捞元素。

修复方案

方案1(无冗余操作,推荐)

完全不需要执行NodeList转数组的操作:在创建li、拿到它的DOM引用时,直接根据索引设置样式即可,省掉不必要的DOM查询和重复转换开销:

const bottles = document.getElementById("bottles");
count = 99;
var myArray = [];
var j = 0;

function bottlesOnTheWall() {
  while (count > 0) {
    if(count > 2) {
      myArray.push(`${count} bottles of beer on the wall, ${count} bottles of beers. Take one down and pass it around, ${count - 1} bottles of beer on the wall`)
    } else if (count === 2) {
      myArray.push(`${count} bottles of beer on the wall, ${count} bottles of beers. Take one down and pass it around, ${count - 1}bottle of beer on the wall`)
    } else if (count === 1) {
      myArray.push(`${count} bottle of beer on the wall, ${count} bottles of beers. No more bottle of beer on the wall`)
    } else {
      myArray.push(`No more bottles of beer on the wall. No more bottles of beer.  Go to the shop and buy some ${count} more.`)
    }
    count--
  }
  while (j < myArray.length) {
    var liElement = document.createElement("li");
    var text = document.createTextNode(myArray[j]);
    liElement.appendChild(text);
    // 直接用持有的li引用设置样式,无需再转DOM集合查找
    if(j % 2) {
      liElement.style.width = "300px";
    } else {
      liElement.style.width = "500px";
    }
    bottles.appendChild(liElement);
    j++;
  }
}
bottlesOnTheWall();

方案2(需要批量处理所有li时的写法)

如果确实需要把所有li转成数组统一处理,要等所有li渲染完成后,从ul容器上获取它的子元素集合(这时候拿到的才是真正的NodeList),再执行数组转换,绝对不要把ul容器本身当集合转换:

// 原循环仅负责创建、追加li,不提前做样式设置
while (j < myArray.length) {
  var liElement = document.createElement("li");
  var text = document.createTextNode(myArray[j]);
  liElement.appendChild(text);
  bottles.appendChild(liElement);
  j++;
}
// 这里获取的才是真正的li集合(NodeList类型)
const allLis = bottles.querySelectorAll('li');
// 两种数组转换方式都可以正常工作
const bottlesArray = Array.from(allLis);
// 批量设置样式
bottlesArray.forEach((li, index) => {
  li.style.width = index % 2 ? "300px" : "500px";
})

这种场景下用扩展运算符转换也是可行的,因为querySelectorAll()返回的是可迭代的NodeList:const bottlesArray = [...bottles.querySelectorAll('li')]


内容的提问来源于stack exchange,提问作者alwaysLearning

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.22 11:24:03