
很多同学第一次接触 CAN302 这门课看到标题里的“电子商务技术”第一反应都是“又要学一堆理论”。结果翻到 Pt.3发现画风突变直接开始讲JavaScript和Bootstrap而且要求你真实地写出一个能跑的电商页面。作为一个带过好几届这门课的人我可以很直接地告诉你这一部分是整门课的分水岭前面学的 HTML 和 CSS 都是静态的到了 JavaScript 这里页面才真正“活”起来而 Bootstrap 则决定了你写出来的东西到底是“网页原型”还是“像样的前端界面”。这篇文章我就围绕 Pt.3 的核心内容把 JavaScript 和 Bootstrap 在电商场景里的应用拆开揉碎了讲一遍。不管是正在上这门课、还是纯粹想做一个电商前端页面的自学党这篇文章能帮你在最短时间内建立完整的实操路线顺便避开我见过无数人踩过的坑。下面进入正题。1. 内容整体设计与思路拆解为什么电商前端绕不开 JS 和 Bootstrap先说一个很现实的情况电子商务系统本质上是一个“展示商品 引导下单”的信息系统而用户接触到的所有界面都跑在浏览器里。HTML 负责内容是骨架CSS 负责样式是皮肤但真正让用户觉得“好用”的操作——加入购物车、切换图片、校验表单、计算总价——全部靠 JavaScript 在浏览器端实时完成。至于 Bootstrap它其实是 CSS 和 JS 组件的集合帮你用标准化的方式快速搭出栅格布局、导航栏、按钮、下拉菜单这些电商页面里反复出现的东西。两者配合就是 Pt.3 的核心内容。从教学设计的角度看这一章安排的思路是先让你对 JavaScript 的语法和操作对象DOM建立基本认知然后立刻用 Bootstrap 把界面撑起来最后两者互相配合完成一个完整的电商页面交互。很多人容易犯的毛病是孤立地学语法学了 var、if、for 就觉得完事了结果一写真实页面就蒙了因为真实页面的核心不是语法而是“事件”和“DOM 操作”。所以我建议你的学习重心从一开始就要放在这两个点上而不是死磕语言本身。另外一个值得注意的点这门课用的开发环境通常比较随意有人用 HBuilder有人用 VS Code还有人直接用记事本。环境差异其实不重要真正重要的是你写的 HTML、CSS、JavaScript 三个文件必须正确关联。我在课上反复强调一个原则HTML 结构、CSS 样式、JS 行为三者分离。用 Bootstrap 的时候很多人图省事把样式全写在 class 里这没错但自己的业务 JS 一定要单独建文件引入否则后面维护和排查问题会非常痛苦。明白了这个整体思路接下来我们一步步拆解 JavaScript 的核心知识点在电商场景里到底怎么用别只抱着语法书啃了。2. JavaScript 核心语法与电商页面交互实战很多同学一上来就翻《JavaScript 高级程序设计》然后就放弃了。这门课不需要这么做。CAN302 阶段你需要掌握的 JS范围非常明确变量与函数、数据类型、DOM 操作、事件监听、简单的数组方法、以及表单验证。我把这几个点结合电商场景逐一展开你会发现每个语法都是为了解决一个具体的界面问题而存在的。2.1 变量、函数与事件让页面“动”起来的基础三件套在电商页面里最简单的交互是什么用户点一下“加入购物车”按钮页面上购物车的角标数字就加一。这个场景背后就是三个基础概念的组合变量保存状态、函数定义行为、事件触发行为。button idaddBtn加入购物车/button span idcartCount0/spanlet count 0; const btn document.getElementById(addBtn); const span document.getElementById(cartCount); btn.addEventListener(click, function() { count; span.textContent count; });这里有几个细节必须注意。第一用let声明变量不要用var这是现代 JavaScript 的基本规范let有块级作用域可以避免很多难以排查的 bug。第二document.getElementById是获取元素最基础的方法务必熟练写复杂页面时可以用querySelector但初学阶段先用getElementById更直观不容易出错。第三addEventListener是绑定事件的推荐方式不要在 HTML 里写onclick...那样会让结构、样式、行为混在一起后面改起来极麻烦。函数是封装逻辑的基本单元。上面例子中我直接写了一个匿名函数实际项目中通常会把逻辑写到命名函数里便于复用和测试function addToCart() { count; span.textContent count; console.log(当前购物车数量 count); } btn.addEventListener(click, addToCart);也许有同学觉得“加购物车角标数字”太简单了但这恰恰是最核心的入门逻辑。后面所有的复杂功能比如购物车总价计算、商品切换、下拉菜单展开本质都是一样的套路一个事件触发一个函数函数里对 DOM 元素做修改。理解了这一点JS 的入门关就算过了。2.2 常用 DOM 操作速查增删改查其实是电商页面的主旋律电商页面里的绝大部分交互都可以用“查、改、增、删”四个字来概括。查document.getElementById、document.querySelector获取页面上的元素。改通过element.textContent改文本通过element.style改样式通过element.src改图片地址通过element.classList.add/remove切换 CSS 类。增document.createElement创建新元素parent.appendChild把它挂到页面上比如动态往商品列表里添加一个商品卡片。删element.remove()移除元素比如用户删除购物车中的某一行商品。以电商页面中非常常见的“商品放大镜”效果为例鼠标悬停在一张小的商品缩略图上旁边显示对应的大图。这个功能的本质就是“改”图片的 srcfunction changeImage(imageSrc) { document.getElementById(mainImg).src imageSrc; }然后在 HTML 给缩略图绑定事件img srcsmall1.jpg onmouseoverchangeImage(big1.jpg)注意我这里在 HTML 里用了onmouseover只是因为这个场景绑定方式简单直观。正式项目中我仍然推荐用addEventListener。不过作为初学者这两者都要看得懂因为你以后会接触到大量网上现成的代码片段几乎都是混合写法。2.3 必备的数组方法filter、map、forEach 在购物车与商品列表中的应用数组方法是很多初学者的拦路虎因为它和传统的 for 循环写法差别较大而且函数式的风格一开始会有点不习惯。但它在电商场景中太常用了只要涉及“列表数据”你就会用到这些方法。举个例子一个电商后台的商品管理页面管理员需要筛选出价格大于 100 元的商品const products [ { name: 无线鼠标, price: 79 }, { name: 机械键盘, price: 299 }, { name: 显示器支架, price: 159 } ]; const expensive products.filter(function(item) { return item.price 100; }); console.log(expensive); // 输出[{ name: 机械键盘, price: 299 }, { name: 显示器支架, price: 159 }]filter不会修改原数组而是返回一个新数组这非常重要避免了你处理数据时不小心把原始数据给改了。再比如forEach用来遍历数组并执行操作。比如把所有商品名称渲染到页面的列表中const list document.getElementById(productList); products.forEach(function(product) { const li document.createElement(li); li.textContent product.name - ¥ product.price; list.appendChild(li); });还有map它和forEach的区别在于map会返回一个新数组。比如你需要把所有商品名称提取成一个纯字符串数组const names products.map(function(product) { return product.name; }); // [无线鼠标, 机械键盘, 显示器支架]这一段我想表达的核心是遇到数组处理的需求时优先考虑这些现代数组方法而不是动手写 for 循环。代码更简洁、意图更清楚而且这些方法在面试和后续课程中都会高频出现早点熟练绝对不吃亏。3. Bootstrap 布局与组件用最快速度搭出像样的电商界面说句实话如果没有 BootstrapCAN302 这个阶段很多同学的作品连“及格”都够呛。Bootstrap 最大的价值不是让你成为 CSS 大神而是让你在完全不懂复杂样式的情况下也能做出响应式的、专业的界面。特别是电商页面这种“栅格化”很强的布局用 Bootstrap 简直是量身定做。3.1 栅格系统电商商品陈列背后的响应式布局原理在 Grid 布局和 Flexbox 普及之前Bootstrap 的栅格系统是前端界事实上的布局标准。即使是现在理解栅格原理仍然很重要因为 Bootstrap 的栅格系统背后是一种很实用的响应式思路把一行分成 12 列按需要分配宽度并且在不同屏幕尺寸下可以选择不同的分配策略。看一个典型的电商商品展示区布局div classcontainer div classrow div classcol-lg-3 col-md-6 col-sm-12 div classcard img srcproduct1.jpg classcard-img-top alt商品1 div classcard-body h5 classcard-title无线鼠标/h5 p classcard-text¥79.00/p a href# classbtn btn-primary加入购物车/a /div /div /div !-- 其他商品卡片 -- /div /div这里的关键是col-lg-3 col-md-6 col-sm-12这三个类。它们的意思是在超大屏lg上每张卡片占 3 列一行能放 4 张卡在中屏md上每张卡片占 6 列一行放 2 张卡在小屏sm及以下每张卡片占满 12 列一行只放 1 张卡。这套规则直接解决了电商页面在不同设备上的展示问题手机用户看到单列大图电脑用户看到整齐的多列陈列体验完全不一样。使用栅格系统时有几个常见的错误值得注意。第一个是忘记写container或row直接把col-*扔在页面上结果布局完全错乱。第二个是搞不懂 12 列的切分逻辑比如你想排 3 列应该用col-*为 4444 12而不是随意填数字。第三个是忽视gutter列间距设置导致卡片之间挤在一起建议在row上使用g-3、g-4这类间距类让卡片之间留出呼吸感。3.2 电商高频组件详解导航栏、卡片、下拉菜单、表格、模态框Bootstrap 的文档非常完善但 CAN302 阶段你最需要掌握的组件其实只有五个导航栏navbar、卡片card、按钮button、下拉菜单dropdown、表格table、模态框modal。下面我用电商场景把每个组件的用法串起来方便你直接套用。导航栏是一个电商页面的门面。Bootstrap 的 navbar 组件可以快速生成一个带 Logo、菜单、搜索框和购物车图标的顶部导航nav classnavbar navbar-expand-lg navbar-light bg-light div classcontainer-fluid a classnavbar-brand href#我的商店/a button classnavbar-toggler typebutton>div classdropdown button classbtn btn-secondary dropdown-toggle typebutton>table classtable table-striped table-hover thead tr th订单号/th th商品名称/th th数量/th th金额/th th状态/th /tr /thead tbody tr td20240001/td td无线鼠标/td td2/td td¥158.00/td td已付款/td /tr /tbody /tabletable-striped给奇偶行加不同底色table-hover让鼠标悬停时高亮当前行这两个类让表格的可读性大大提升而且零成本实现。模态框就是你常见的“弹窗”电商里常用于购物车确认或者商品详情快速预览。Bootstrap 的模态框使用>button typebutton classbtn btn-primary>.badge-hot { position: absolute; top: 10px; right: 10px; background-color: #ff4444; color: #fff; padding: 4px 10px; border-radius: 4px; font-size: 14px; }然后在 HTML 的card容器里加上这个元素。为什么这件事值得专门提出来因为很多初学者容易走极端要么完全依赖框架遇到一点特殊需求就卡死要么完全抛弃框架自己从零写样式结果效率极低。正确的姿势是用框架解决 80% 的通用问题用自定义代码解决 20% 的业务特色。这个边界意识在真实的电商开发团队里同样是核心能力。4. 完整实战JS 与 Bootstrap 协同实现一个电商商品展示与购物车交互前面拆解了语法和组件现在把它们串起来。这一节用一个小而完整的案例把 JavaScript 和 Bootstrap 的合作过程完整过一遍。这个案例基本可以覆盖 CAN302 Pt.3 课程设计中 50% 的需求——商品展示、下拉筛选、加入购物车、总价计算。4.1 目标与思路做一个用户可以选商品、加购物车、算总价的页面我们做一个极简但五脏俱全的“零食商店”页面页面包含以下功能用 Bootstrap 栅格展示 6 个商品卡片每个卡片上有商品名、价格和“加入购物车”按钮。页面顶部是一个下拉菜单可以选择“全部”“饼干”“饮料”三个分类选择后只显示对应分类的商品。页面右侧是购物车面板点击“加入购物车”后商品被添加到购物车列表中并实时计算总价。所有商品数据都放在一个 JavaScript 数组里。这样做的意义在于页面的内容不是写死在 HTML 里的而是从数据模型动态渲染出来的这是后面学习任何前端框架Vue、React之前必须建立的核心思维方式——数据驱动视图。4.2 实现步骤拆解从数据定义到动态渲染再到购物车逻辑第一步创建index.html引入 Bootstrap 的 CSS 和 JS。注意引入顺序很关键先 Bootstrap CSS再自己的 CSS先 Bootstrap JS再自己的 JS。引入 JS 的时候如果你的脚本需要操作 DOM一般放在body末尾或者使用defer属性。!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title零食商店/title link hrefhttps://cdn.jsdelivr.net/npm/bootstrap5.3.0/dist/css/bootstrap.min.css relstylesheet /head body !-- 页面内容 -- script srchttps://cdn.jsdelivr.net/npm/bootstrap5.3.0/dist/js/bootstrap.bundle.min.js/script script srcapp.js/script /body /html在app.js中定义商品数据。这里的数据结构是数组加对象每个对象代表一个商品const products [ { id: 1, name: 经典原味曲奇, category: 饼干, price: 12.5 }, { id: 2, name: 巧克力夹心饼, category: 饼干, price: 15.0 }, { id: 3, name: 抹茶威化, category: 饼干, price: 18.0 }, { id: 4, name: 冰镇柠檬茶, category: 饮料, price: 6.5 }, { id: 5, name: 橙汁饮料, category: 饮料, price: 8.0 }, { id: 6, name: 气泡苏打水, category: 饮料, price: 5.5 } ];然后定义渲染函数。这个函数接收一个商品数组作为参数把它渲染到页面上的row容器中。如果传入的空数组就显示一个“暂无商品”的提示function renderProducts(list) { const container document.getElementById(productRow); container.innerHTML ; if (list.length 0) { container.innerHTML div classcol-12 text-center py-5没有符合条件的商品/div; return; } list.forEach(function(product) { const col document.createElement(div); col.className col-lg-4 col-md-6 col-sm-12 mb-4; col.innerHTML div classcard h-100 div classcard-body d-flex flex-column h5 classcard-title${product.name}/h5 p classcard-text text-muted分类${product.category}/p p classcard-text fs-5 fw-bold text-danger¥${product.price.toFixed(2)}/p button classbtn btn-primary mt-auto onclickaddToCart(${product.id})加入购物车/button /div /div ; container.appendChild(col); }); }注意我在渲染商品卡片时直接使用了模板字符串反引号这是 ES6 语法比字符串拼接更直观。${product.name}这种写法可以直接把变量的值嵌到字符串里。此外我在这里用了onclickaddToCart(${product.id})是为了在渲染时直接传商品 ID 进去简单明确虽然前面我说推荐addEventListener但动态渲染的场景下用内联事件也常见你需要能看懂。接下来定义购物车相关逻辑。购物车用数组保存每个元素包含商品信息和数量。加入购物车时先检查是否已经存在如果存在就把数量加一否则新增let cart []; function addToCart(productId) { const product products.find(function(p) { return p.id productId; }); if (!product) return; const existing cart.find(function(item) { return item.id productId; }); if (existing) { existing.quantity; } else { cart.push({ ...product, quantity: 1 }); } renderCart(); }renderCart负责把购物车列表渲染出来同时计算总价function renderCart() { const cartItems document.getElementById(cartItems); const totalPrice document.getElementById(totalPrice); if (cart.length 0) { cartItems.innerHTML li classlist-group-item text-center text-muted购物车是空的/li; totalPrice.textContent ¥0.00; return; } let total 0; let html ; cart.forEach(function(item) { const subtotal item.price * item.quantity; total subtotal; html li classlist-group-item d-flex justify-content-between align-items-center div div${item.name}/div small classtext-muted${item.price.toFixed(2)} × ${item.quantity}/small /div div span classme-2¥${subtotal.toFixed(2)}/span button classbtn btn-sm btn-outline-danger onclickremoveFromCart(${item.id})删除/button /div /li ; }); cartItems.innerHTML html; totalPrice.textContent ¥ total.toFixed(2); }这里用到了前面讲的forEach和模板字符串也体现了“数据驱动视图”的思路每次动作只修改cart数组然后调用renderCart重新渲染整个购物车区域。较真的同学可能会觉得每次都整体重绘不够高性能但对这门课的场景来说完全够了而且思路极其清晰。最后加上删除购物车商品和下拉筛选的逻辑function removeFromCart(productId) { cart cart.filter(function(item) { return item.id ! productId; }); renderCart(); } function filterProducts() { const category document.getElementById(categorySelect).value; if (category all) { renderProducts(products); } else { const filtered products.filter(function(product) { return product.category category; }); renderProducts(filtered); } }页面上筛选下拉框绑定onchangefilterProducts()即可。到这里一个完整的“商品展示 分类筛选 购物车增删 总价计算”的小应用就完成了。这段代码我不建议你直接复制走而是建议你亲手敲一遍敲的过程你会理解每一行的作用也会顺手发现语法错误这种学习效率远高于看十遍教材。4.3 性能与体验优化两个值得立即养成的编码习惯写这个案例的同时还有两件小事值得养成习惯。第一操作 DOM 的次数要尽量少。在实际项目中频繁操作 DOM 是性能瓶颈的大户所以你看到我在renderCart()里是先拼一个字符串最后一次用innerHTML赋值而不是循环里每次appendChild。这个习惯从入门阶段就建立起来后面写复杂项目会受益很多。第二toFixed(2)处理金额显示时有一个小坑它返回的是字符串。比如(6.5).toFixed(2)返回的是6.50而不是数字6.5。如果后续还要做计算必须用parseFloat转回数字。我在上面案例中都是最后展示时才使用toFixed(2)中间计算全部用原始数字这是一个很重要的细节注意不要弄反了。5. 常见问题与排查技巧开发环境、报错与版本踩坑实录写这部分之前我特意把历届学生反馈过的问题翻了一下下面的内容基本覆盖了 90% 的常见报错和疑难杂症。按出现频率从高到低排序一条一条说。5.1 高频报错排查速查表我把最常见的几类问题整理成一个速查表你遇到问题先对照着检查现象最可能的原因排查思路页面没有样式Bootstrap CDN 链接写错或只引入了 CSS 没引 JS浏览器按 F12网络面板里看 CSS 是否加载成功检查链接地址下拉、模态框点击无反应没有引入 Bootstrap 的 JS 文件或者引入位置不对确认bootstrap.bundle.min.js已经正确引入且放在自己的 JS 之前自行编写的 JS 没生效脚本在 DOM 加载前执行找不到元素把script放到 body 末尾或者用window.onload/defer提示Cannot read properties of nullgetElementById里写的 ID 和 HTML 中的 ID 不一致仔细核对引号里的字符串区分大小写检查 HTML 元素有没有写 ID点击按钮页面刷新按钮默认类型是submit触发了表单提交给按钮加typebutton或在事件处理函数里调用event.preventDefault()SyntaxError: Unexpected token多半是中英文符号混用或者引号没闭合检查报错出现的行号看是不是用了中文逗号、引号或括号下拉筛选没有效果商品的category值和下拉选项的value不匹配在函数调用处打印category变量的值对照商品的分类字段这个表格可以当成“急救手册”存下来每一类问题都是真实项目里反复出现的。特别是“按钮点击页面刷新”这一项因为很多同学把按钮装在form里忘了加typebutton结果一按“加入购物车”页面就刷新了所有状态全部重置自己还百思不解。5.2 前端调试基本功打开浏览器开发者工具排查 JS 错误有同学花 20 分钟写代码却花 2 小时在干瞪眼找 bug。我建议所有人都养成一个习惯代码跑不动先按 F12 打开浏览器开发者工具然后看 Console 控制台。控制台会直接告诉你哪一行报什么错绝大多数问题在 Console 里一目了然。console.log()是最朴素的调试手段但也是最高效的。我写前端这么多年调试新代码时还是经常靠console.log输出关键变量来确认逻辑走到了哪一步。比如下拉筛选不生效就在函数开头打印一下用户选择的分类值function filterProducts() { const category document.getElementById(categorySelect).value; console.log(当前选择, category); // 后续逻辑 }如果 Console 里什么输出都没有说明函数压根没被触发——这时候检查的是事件绑定或元素的onchange属性有没有正确写在 HTML 上。另外还有一个非常实际的建议如果你看到Failed to load module script相关报错很可能是你用 ES6 module 方式引入了 JSscript typemodule但服务端没有正确返回 JavaScript MIME 类型。这门课阶段大概率不需要 module 模式直接普通引入script srcapp.js/script即可别给自己加戏。5.3 开发环境与前端框架在课程阶段最容易踩的三个坑第一个坑是试图在本阶段引入 jQuery。我理解大家为什么想用 jQuery网上有大量旧教程和插件都用 jQuery而且看语法好像比原生 JS 简洁一些。但 CAN302 这门课的考察重点就是原生 JavaScript 能力考试和课程设计都要求使用原生 DOM 操作。引入 jQuery 只会让你在考试时露怯而且还会增加一个库加载失败的风险点。我的建议非常明确这个阶段老老实实用原生 JS。第二个坑是盲目追求现代化的打包工具。有的同学看到网上的教程都是用 npm、webpack、Vite就想着我也要搞一个工程化的项目。这个出发点不错但在课程阶段时间有限如果花大量时间折腾工具链很可能到交作业那天页面还没跑起来。这门课的作业用最简单的“三个文件放一个文件夹”就完全可以搞定工具链不是加分项而是风险项。真想学工程化等课程结束之后再系统补不迟。第三个坑是在 HBuilder 这类工具里遇到路径问题。HBuilder 自带一个简易服务器如果你直接在文件管理器里双击打开 HTML部分浏览器会限制本地脚本加载导致样式或 JS 不生效。这时候要么在 HBuilder 里“运行到浏览器”要么用 VS Code 的 Live Server 插件本质上都是为了搞一个本地 HTTP 服务环境。学会用本地服务器跑前端项目以后任何前端开发都少踩很多坑。5.4 表单验证实战JavaScript 校验与 HTML5 内置验证的取舍前面热词里出现了一个很典型的问题“JavaScript 中表单提交和 H5 的区别”。这几乎是每届学生都会问的问题也确实是个容易混淆的考点。HTML5 自带一套表单验证机制比如在input上设置required、typeemail、minlength等属性浏览器会在提交时自动校验并弹出提示form idcheckoutForm div classmb-3 label classform-label邮箱/label input typeemail classform-control required /div div classmb-3 label classform-label收货地址/label input typetext classform-control required minlength5 /div button typesubmit classbtn btn-primary提交订单/button /form这种方案的好处是零 JavaScript、浏览器原生支持、UI 体验统一。但它的定制能力非常弱比如你想在表单提交之前先检查购物车是否为空、想验证手机号是否符合中国区号规则、想在提交时弹出一个自定义的二次确认弹窗这套内置验证就远远不够了。这时候就需要用 JavaScript 手动接管表单的提交事件document.getElementById(checkoutForm).addEventListener(submit, function(event) { event.preventDefault(); // 阻止默认提交 const email document.getElementById(email).value; const address document.getElementById(address).value; if (!email) { alert(请填写邮箱地址); return; } if (address.length 5) { alert(收货地址至少需要 5 个字符); return; } if (cart.length 0) { alert(购物车为空无法提交订单); return; } // 所有校验通过执行真正的提交逻辑 alert(订单提交成功); });这里最核心的语句是event.preventDefault()它的作用是阻止浏览器的默认行为。具体到这个场景就是阻止表单把数据提交到服务器并刷新页面让你有机会在提交前先执行自己的校验逻辑。理解了preventDefault()你不仅搞定了表单验证还能顺便理解很多其他需要“拦截默认行为”的场景比如阻止链接跳转、阻止右键菜单等。说句实在话不知道preventDefault()的人写表单验证时一定痛苦不堪因为你会发现自己的代码怎么也插不进“提交前做检查”这个环节。而在真实的电商系统中表单验证往往是第一道安全防线一个完全没有前端校验的下单页面基本等于向用户敞开大门请你往数据库里写垃圾数据。所以这一块虽然有偏基础但它背后的思维校验时机、默认行为拦截、前后端校验的一致性值得每个初学者认真对待。6. 一些额外想对初学者说的话写到这儿核心内容基本已经覆盖完毕。最后分享一点个人体会也算是在许多届学生身上验证过的经验JavaScript 和 Bootstrap 这门课程最重要的不是背下来多少个 API而是建立“把 UI 界面拆成结构HTML 表现CSS 行为JS三个层面”的思维方式。你会渐渐发现所有页面交互本质上都是“监听某个事件、改变数据、重新渲染”想通了这一层后面的路会越走越顺。同时这个阶段请一定、一定多动手敲代码。看十遍教程不如把图表中的例子亲手跑一遍把代码故意写错几处再看报错这些试错过程的积累比任何网课都有价值。课程设计的时候哪怕只是一个简单的商品列表加购物车也建议花力气把代码写整洁、把逻辑写严谨因为这些东西在面试时随手就能拿出来讲会成为你的加分项。加油动手写吧。