阅读视图

发现新文章,点击刷新页面。

JavaScript篇:for...in vs for...of:遍历JavaScript数据的正确姿势,你踩坑了吗?

        大家好,我是江城开朗的豌豆,一名拥有6年以上前端开发经验的工程师。我精通HTML、CSS、JavaScript等基础前端技术,并深入掌握Vue、React、Uniapp、Flutter等主流框架,能够高效解决各类前端开发问题。在我的技术栈中,除了常见的前端开发技术,我还擅长3D开发,熟练使用Three.js进行3D图形绘制,并在虚拟现实与数字孪生技术上积累了丰富的经验,特别是在虚幻引擎开发方面,有着深入的理解和实践。

        我一直认为技术的不断探索和实践是进步的源泉,近年来,我深入研究大数据算法的应用与发展,尤其在数据可视化和交互体验方面,取得了显著的成果。我也注重与团队的合作,能够有效地推动项目的进展和优化开发流程。现在,我担任全栈工程师,拥有CSDN博客专家认证及阿里云专家博主称号,希望通过分享我的技术心得与经验,帮助更多人提升自己的技术水平,成为更优秀的开发者。

大家好,我是前端开发工程师小杨。今天咱们来聊聊 JavaScript 里两个看似相似但完全不同的循环语句——for...in 和 for...of

你是不是也曾经纠结过:

  • for...in 和 for...of 到底该用哪个?
  • 为什么有时候遍历数组会得到奇怪的结果?
  • 遍历对象时,哪种方式更安全?

别急,看完这篇你就全懂了!


1. 一句话总结区别

  • for...in → 遍历对象的可枚举属性(包括原型链)
  • for...of → 遍历可迭代对象的值(Array、Map、Set等)

简单来说:

  • for...in 适合对象(但要注意原型链问题)
  • for...of 适合数组、字符串等可迭代结构

2. for...in:遍历对象的“家底”

for...in 会遍历对象的所有可枚举属性,包括继承自原型链的属性

🌰 举个栗子:遍历对象

const user = { name: '我', age: 25, role: 'developer' };

for (const key in user) {
  console.log(key, user[key]); 
}
// 输出:
// name 我
// age 25
// role developer

看起来没问题?但如果原型链上有属性呢?

Object.prototype.customProp = '来自原型链';

for (const key in user) {
  console.log(key); 
}
// 输出:
// name
// age
// role
// customProp (意外多了一个属性!)

解决方案:用 hasOwnProperty 过滤

for (const key in user) {
  if (user.hasOwnProperty(key)) { // 只遍历自己的属性
    console.log(key);
  }
}
// 输出:
// name
// age
// role

⚠️ 注意:for...in 不保证顺序!

  • 对象的属性遍历顺序不固定(尤其是数字键时)
  • 如果需要顺序,改用 Object.keys() + for...of

3. for...of:专治可迭代对象

for...of 专门用于遍历可迭代对象(Iterable) ,比如:
✅ Array
✅ String
✅ Map / Set
✅ NodeList(DOM 元素集合)
✅ arguments 对象

🌰 举个栗子:遍历数组

const skills = ['JS', 'CSS', 'React'];

for (const skill of skills) {
  console.log(skill);
}
// 输出:
// JS
// CSS
// React

比 for...in 更安全,不会遍历到奇怪的东西!

🌰 再举个栗子:遍历字符串

const name = '我';

for (const char of name) {
  console.log(char);
}
// 输出:
// 我

🚫 for...of 不能直接遍历普通对象!

const user = { name: '我' };

for (const val of user) { // ❌ 报错!
  console.log(val);
}
// TypeError: user is not iterable

解决方案:用 Object.values() / Object.entries()

for (const val of Object.values(user)) {
  console.log(val); // 输出:我
}

4. 对比总结

特性 for...in for...of
适用对象 普通对象(会遍历原型链) 可迭代对象(Array、Map、Set等)
返回值 键名(key) 值(value)
顺序保证 ❌ 不保证顺序(尤其数字键) ✅ 保证顺序
原型链问题 可能遍历到继承属性(需过滤) 不会遍历原型链
适用场景 遍历对象属性 遍历数组、字符串等

5. 最佳实践

✅ 用 for...in 时:

  • 一定要加 hasOwnProperty 检查,避免原型链污染
  • 不要用于数组(顺序不可控,可能遍历到非数字键)

✅ 用 for...of 时:

  • 优先用于数组、字符串、Map、Set
  • 普通对象先用 Object.keys() / Object.values() 转换

6. 终极选择指南

场景 推荐方式
遍历对象属性 for...in + hasOwnProperty
遍历数组值 for...of
遍历字符串字符 for...of
遍历Map/Set for...of
需要索引的数组遍历 for 循环 或 forEach

7. 总结

  • for...in → 遍历对象属性(小心原型链)
  • for...of → 遍历可迭代对象的值(数组、字符串等)
  • 普通对象想用 for...of  先用 Object.keys() / Object.values() 转换

🚀 现在你彻底搞懂了吧?下次写循环时别再选错了!

你在使用 for...in 或 for...of 时踩过什么坑?欢迎评论区分享!  👇

JavaScript篇:"三次握手和四次挥手:TCP 连接的‘恋爱仪式’全解析!"

        大家好,我是江城开朗的豌豆,一名拥有6年以上前端开发经验的工程师。我精通HTML、CSS、JavaScript等基础前端技术,并深入掌握Vue、React、Uniapp、Flutter等主流框架,能够高效解决各类前端开发问题。在我的技术栈中,除了常见的前端开发技术,我还擅长3D开发,熟练使用Three.js进行3D图形绘制,并在虚拟现实与数字孪生技术上积累了丰富的经验,特别是在虚幻引擎开发方面,有着深入的理解和实践。

        我一直认为技术的不断探索和实践是进步的源泉,近年来,我深入研究大数据算法的应用与发展,尤其在数据可视化和交互体验方面,取得了显著的成果。我也注重与团队的合作,能够有效地推动项目的进展和优化开发流程。现在,我担任全栈工程师,拥有CSDN博客专家认证及阿里云专家博主称号,希望通过分享我的技术心得与经验,帮助更多人提升自己的技术水平,成为更优秀的开发者。

大家好,我是前端开发工程师小杨。今天咱们来聊聊 TCP 连接的建立和断开,也就是传说中的三次握手(Three-way Handshake)四次挥手(Four-way Handshake)

你可能觉得这是后端的事情,但前端也得懂点网络知识,尤其是调试接口慢、连接异常时,知道底层原理才能更快定位问题!


1. TCP 连接:像谈恋爱一样严谨

TCP(传输控制协议)是一种可靠的传输协议,就像两个人谈恋爱,得先确认彼此心意(三次握手),分手时也要好好告别(四次挥手)。

🌰 举个栗子:我和服务器谈恋爱

  • 三次握手:我和服务器互相确认,建立稳定连接
  • 四次挥手:我和服务器和平分手,确保数据不丢失

2. 三次握手:TCP 的“确认眼神”

三次握手的目标是确保客户端和服务器都能正常收发数据

流程:

  1. 第一次握手(SYN)

    •  → 服务器:SYN=1, seq=x(“嗨,能听到我吗?”)
    • 进入 SYN_SENT 状态
  2. 第二次握手(SYN+ACK)

    • 服务器 → 我:SYN=1, ACK=1, seq=y, ack=x+1(“听到了!你也能听到我吗?”)
    • 服务器进入 SYN_RCVD 状态
  3. 第三次握手(ACK)

    •  → 服务器:ACK=1, seq=x+1, ack=y+1(“听到了!咱们开始聊天吧!”)
    • 双方进入 ESTABLISHED 状态,连接建立!

为什么是三次?两次不行吗?

  • 两次握手:服务器无法确认我是否能收到它的回复(可能我早就断开了)
  • 三次握手:确保双方都能正常收发数据,避免资源浪费

3. 四次挥手:TCP 的“和平分手”

TCP 连接断开时,需要确保数据全部传输完毕,不能突然“拉黑”。

流程:

  1. 第一次挥手(FIN)

    •  → 服务器:FIN=1, seq=u(“我要走了,拜拜!”)
    • 进入 FIN_WAIT_1 状态
  2. 第二次挥手(ACK)

    • 服务器 → 我:ACK=1, ack=u+1(“好的,等我处理完最后的数据”)
    • 服务器进入 CLOSE_WAIT 状态
    • 进入 FIN_WAIT_2 状态
  3. 第三次挥手(FIN)

    • 服务器 → 我:FIN=1, ACK=1, seq=v, ack=u+1(“我也准备好了,再见!”)
    • 服务器进入 LAST_ACK 状态
  4. 第四次挥手(ACK)

    •  → 服务器:ACK=1, ack=v+1(“好的,正式断开!”)
    • 进入 TIME_WAIT 状态(等待 2MSL 后彻底关闭)

为什么是四次?三次不行吗?

  • 服务器可能还有数据要发送,不能直接断开
  • 四次挥手确保双方都完成数据收发,避免数据丢失

4. 常见面试题

Q1:为什么 TIME_WAIT 要等 2MSL?

  • MSL(Maximum Segment Lifetime)  是数据包在网络中的最大存活时间

  • 等待 2MSL 是为了:

    • 确保最后一个 ACK 到达服务器(如果丢失,服务器会重发 FIN)
    • 让旧连接的数据包彻底消失,避免影响新连接

Q2:握手能变成两次吗?挥手能变成三次吗?

  • 握手不能两次(无法确认客户端能收到服务器的回复)
  • 挥手有时能三次(如果服务器没有数据要发,FIN 和 ACK 可以合并)

5. 总结

  • 三次握手:建立连接,确保双方都能通信
  • 四次挥手:断开连接,确保数据不丢失
  • TIME_WAIT:防止旧连接干扰新连接

🚀 前端也要懂点网络知识!  下次遇到接口慢、连接异常时,想想是不是 TCP 的“恋爱仪式”出了问题~

你有遇到过 TCP 相关的问题吗?欢迎评论区交流!  👇

❌