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

请求解决Cannot read property 'filter' of undefined筛选错误

嘿,我帮你定位到问题啦!你遇到的Cannot read property 'filter' of undefined错误,核心原因是全局的phones变量从来没有被正确赋值,一直处于undefined状态。

问题拆解:

你在代码开头声明了let phones;,但在parseJSON函数里,你把传入的JSON数据参数也命名为phones——这就导致这个参数覆盖了全局的phones变量,全局的phones始终是空的。当你提交表单触发筛选时,getFilteredPhones函数尝试调用phones.filter(),自然就会抛出错误。

另外还有几个小问题需要修复:

  1. 你的createPhone函数是用来创建单个手机卡片的,但你在提交表单时直接把筛选后的数组传给它,没有遍历处理,会导致渲染失败。
  2. 筛选逻辑里没有处理“All”选项的情况,选择“All”时不会显示所有手机。
  3. createPhone里的$librand和$liyear没有用const声明,会变成全局变量,可能引发意外问题。

修复后的完整代码:

JavaScript 部分

{ 
  let phones; 

  const initValidation = () => { 
    const $form = document.querySelector(`form`); 
    $form.noValidate = true; 
    $form.addEventListener(`submit`, handleSubmitForm); 
  }; 

  const handleSubmitForm = e => { 
    const $form = e.target; 
    e.preventDefault(); 
    if($form.checkValidity()){ 
      const filteredPhones = getFilteredPhones(); 
      // 清空之前的手机列表,避免叠加显示
      const $section = document.querySelector(`section`);
      $section.innerHTML = '';
      // 遍历筛选后的数组,创建每个手机卡片
      filteredPhones.forEach(phone => createPhone(phone));
    } 
  }; 

  const getFilteredPhones = () => { 
    const brand = document.querySelector(`.brands`).value; 
    // 处理“All”选项,返回所有手机
    if (brand === "All") {
      return [...phones];
    }
    return phones.filter(phone => phone.brand === brand); 
  }; 

  const setBrandOptions = brands => { 
    const $select = document.querySelector(`.brands`); 
    brands.sort().forEach(brand => { 
      const $option = document.createElement(`option`); 
      $option.value = brand; 
      $option.textContent = brand; 
      $select.appendChild($option); 
    }); 
  }; 

  const getUniqueBrands = phones => { 
    const uniqueBrands = []; 
    phones.forEach(phone => { 
      if(!uniqueBrands.includes(phone.brand)){ 
        uniqueBrands.push(phone.brand); 
      } 
    }); 
    return uniqueBrands; 
  }; 

  const createPhone = phone => { 
    const $div = document.createElement(`div`); 
    document.querySelector(`section`).appendChild($div); 

    const $img = document.createElement(`img`); 
    $img.setAttribute('src', phone.image); 
    $div.appendChild($img); 

    const $title = document.createElement(`h2`); 
    $title.textContent = phone.name; 
    $div.appendChild($title); 

    const $ul = document.createElement(`ul`); 
    $div.appendChild($ul); 

    // 加上const声明,避免全局变量
    const $librand = document.createElement(`li`); 
    $librand.textContent = phone.brand; 
    $ul.appendChild($librand); 

    const $liyear = document.createElement(`li`); 
    $liyear.textContent = phone.year; 
    $ul.appendChild($liyear); 
  }; 

  const parseJSON = (jsonPhones) => { 
    // 把全局的phones赋值为获取到的JSON数据
    phones = jsonPhones;
    phones.forEach(phone => createPhone(phone)); 
    const brands = getUniqueBrands(phones); 
    setBrandOptions(brands); 
  }; 

  const initJSON = () => { 
    const url = "assets/data/phones.json"; 
    fetch(url) 
      .then(r => r.json()) 
      .then(jsonObject => parseJSON(jsonObject)); 
  }; 

  const init = () => { 
    initJSON(); 
    initValidation(); 
  }; 

  init(); 
}

CSS 部分(保留原代码)

body{ 
  display: flex; 
  flex-direction: column; 
  align-items: center; 
  justify-content: center; 
} 
section{ 
  display: flex; 
  flex-direction: row; 
  justify-content: space-around; 
  align-items: flex-end; 
} 
div{ 
  display: flex; 
  flex-direction: column; 
  padding-left: 3rem; 
  padding-right: 3rem; 
} 
h1{ 
  border-bottom: .1rem solid black; 
  padding-right: 1rem; 
  padding-left: 1rem; 
  margin-bottom: 3rem; 
} 
img{ 
  margin-bottom: 1rem; 
  height: 100%; 
  width: 100%; 
} 
h2{ 
  font-family: sans-serif; 
  margin-left: 1rem; 
  font-size: 1.3rem; 
} 
ul{ 
  margin-left: 1rem; 
} 
select{ 
  margin-bottom: 2rem; 
}

HTML 部分(保留原代码)

<!DOCTYPE html> 
<html lang="en" dir="ltr"> 
<head> 
  <meta charset="utf-8"> 
  <title></title> 
  <link rel="stylesheet" href="css/reset.css"> 
  <link rel="stylesheet" href="css/style.css"> 
</head> 
<body> 
  <h1>My Phone Collection</h1> 
  <form action=""> 
    <label for="brands">Brand: 
      <select id="brands" class="brands input"> 
        <option value="All">All</option> 
      </select> 
      <span class="error"></span> 
    </label> 
    <button type="submit">Search</button> 
  </form> 
  <section></section> 
  <script type="text/javascript" src="js/script.js"></script> 
</body> 
</html>

关键修改点总结:

  1. 把parseJSON的参数名改为jsonPhones,并将全局phones赋值为这个参数,确保全局变量有数据。
  2. 在handleSubmitForm里先清空section内容,再遍历筛选后的数组创建手机卡片。
  3. 给getFilteredPhones添加“All”选项的处理逻辑。
  4. 给createPhone里的两个列表项变量加上const声明,避免全局变量泄漏。

这样修改后,你的筛选功能应该就能正常工作啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:43:37