找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4684

积分

0

好友

621

主题
发表于 2 小时前 | 查看: 3| 回复: 0

这是一道字节跳动的面试题,乍一看是不是觉得熟悉又陌生?很多人第一反应可能会懵住。

JavaScript 中,解构赋值语法的左侧是一个数组,而右侧则应该是一个具有迭代器接口的对象(如数组、Map、Set等)。因此,将对象 {a: 1, b: 2} 解构赋值给 [a, b] 会导致语法错误。但面试官偏偏要求让这个等式成立,这背后考察的正是对 ES6+ 核心特性的深入理解。

解题思路

错误思路

既然将一个对象解构赋值给数组会报错,那是不是直接把语法改成对象的解构就行了?比如写成 var { a, b } = { a: 1, b: 2 };

如果真这么做了,那恭喜你,面试可能就到此为止了。这道题的考点远不止于此。

正确思路:从报错信息入手

我们先看看直接执行会报什么错:

var [a, b] = {a: 1, b: 2}
// TypeError: {(intermediate value)(intermediate value)} is not iterable

错误明确指出,右侧的对象 (intermediate value) 是不可迭代的(not iterable)。这直接点明了问题的关键:对象默认不具备迭代器属性

为了加深理解,我们看一个 for...of 循环的例子:

let arr = [1, 2, 3]
let obj = {
    a: 1,
    b: 2,
    c: 3
}
for(let item of arr){
    console.log(item) // 正常输出 1, 2, 3
}
for(let item of obj){
    console.log(item) // TypeError: obj is not iterable
}

我们知道 for...of 只能遍历具有迭代器接口的数据结构。那么,数组身上的迭代器属性到底是什么样的呢?我们可以在控制台查看数组的原型。

浏览器控制台查看数组原型方法,包含Symbol.iterator属性

从上图可以看到,数组原型(Array.prototype)上有一个 Symbol.iterator 属性,它的值是一个函数。如果我们调用这个函数会得到什么?

console.log(arr.__proto__[Symbol.iterator]());
// Object [Array Iterator] {}

关键点来了:它返回的是一个迭代器对象!

所以,一个可迭代对象的基本结构是这样的:

interable
{
    [Symbol.iterator]: function () {
        return 迭代器 // 一个具有next()方法的对象
    }
}

由此我们可以得出结论:一个数据结构只要具备 [Symbol.iterator] 属性,且其值是一个能返回迭代器对象的函数,那它就是可迭代的。

实现:让对象变得可迭代

回到面试题,目标是让 var [a, b] = {a: 1, b: 2} 成立。思路很明确了:为对象手动添加一个迭代器,也就是让对象能够通过某种方式“继承”或拥有迭代器属性。

我们可以直接在 Object.prototype 上添加这个方法,但这会影响到所有对象,需要谨慎考虑其副作用。不过,为了解题,我们可以先这样做:

Object.prototype[Symbol.iterator] = function(){
    // 暂时为空
}

var [a, b] = {a: 1, b: 2}
console.log(a, b);

此时,错误信息变了:

TypeError: Result of the Symbol.iterator method is not an object

这说明我们的方向是对的,但 [Symbol.iterator] 方法没有返回一个正确的迭代器对象。

我们知道 var [a, b] = [1, 2] 是完全可以的。所以,最直接的思路是让对象的迭代器行为模仿数组。我们可以让对象的迭代器返回其属性值的迭代器。使用 Object.values(this) 可以获取对象的所有值,形成一个数组,而这个数组天然就是可迭代的。

Object.prototype[Symbol.iterator] = function(){
    // 使用 Object.values(this) 获取对象的所有值,并返回这些值的迭代器对象
    return Object.values(this)[Symbol.iterator]()
}

var [a, b] = {a: 1, b: 2}
console.log(a, b); // 输出:1 2

成功! 这段代码的核心是重写了 Object.prototype 上的 [Symbol.iterator] 方法。新的方法通过 Object.values(this) 获取调用它的对象的所有值([1, 2]),然后调用这个值数组自身的迭代器方法并返回其结果。这样,任何对象在被数组解构或用于 for...of 循环时,都会遍历其属性值。

总结与思考

这道题巧妙地考察了对 JavaScript 迭代协议(Iteration Protocols) 的理解。解构赋值、for...of、扩展运算符(...)等语法都依赖于可迭代对象。理解 Symbol.iterator 这个内部符号是如何工作的,是掌握现代 JavaScript 异步编程和高级数据操作的基础。

在实际项目中,我们通常不会直接修改 Object.prototype,因为这会造成全局污染,影响所有对象。更安全的做法是为特定对象单独添加迭代器,或者使用 MapSet 这类内置的可迭代数据结构。

解决这类“熟悉又陌生”的面试题,关键在于将知识点串联起来,从错误信息中定位核心概念(本例中是“not iterable”),并利用对语言底层机制(如迭代器)的理解来构建解决方案。希望这个解析能帮助你在未来的技术面试中更加从容。如果你对这类 JavaScript 深入原理的讨论感兴趣,欢迎到 云栈社区HTML/CSS/JS 板块与其他开发者交流探讨。




上一篇:硬件研发总监如何系统化推进核心技术攻关:全流程指南与实践模板
下一篇:Java新特性前瞻:基于Amber项目的命令式模式匹配,为日常编码带来解构赋值新范式
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-3-27 06:47 , Processed in 0.551863 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表