JS中keys()、values()、entries()与Symbol.iterator有什么区别
JavaScript 可迭代对象判定与迭代相关方法的核心差异
可迭代/非可迭代对象的划分标准
JavaScript 中两类对象的判定边界非常清晰:
- 实现了
Symbol.iterator()方法的对象,属于可迭代对象 - 未实现该方法的对象,属于非可迭代对象
判定的核心依据是:Symbol.iterator()方法调用后会返回符合迭代协议的迭代器对象。
内置知名Symbol
Symbol.iterator的官方定义为:用于指定对象的默认迭代器,供for...of等语法在遍历时自动调用。
易混淆方法的核心差异
数组、Map、Set等内置可迭代对象的原型上,除了Symbol.iterator()之外,还同时存在keys()、values()、entries()三个方法,这几个方法调用后同样会返回迭代器对象,很容易让人混淆二者的作用,核心差异主要有两点:
- 触发逻辑不同:
Symbol.iterator()是迭代协议约定的默认入口,是JS引擎执行隐式遍历操作时唯一会自动调用的方法——不管是for...of循环、数组展开...、解构赋值,还是Array.from()这类接收可迭代对象的API,底层都会先取对象的Symbol.iterator()执行拿到迭代器,不需要开发者手动调用;而keys()、values()、entries()属于手动调用的工具方法,只有显式执行时才会返回对应规则的迭代器,不会被引擎的隐式遍历逻辑识别。 - 遍历规则的绑定逻辑不同:
Symbol.iterator()返回的迭代器,遵循的是对象预设的默认遍历规则,比如数组默认遍历值、Map默认遍历键值对,开发者也可以手动重写对象的Symbol.iterator来修改默认遍历行为;而三个工具方法的遍历规则是固定的,分别对应遍历键、遍历值、遍历键值对,不会受Symbol.iterator重写的影响。
可以通过一段简单的代码验证这个差异:
const demoArr = ['x', 'y', 'z'] // 隐式调用默认迭代器,按数组默认规则遍历值 for (const i of demoArr) { console.log(i) // 依次输出 x y z } // 重写默认迭代器逻辑 demoArr[Symbol.iterator] = function* () { yield '自定义内容1' yield '自定义内容2' } // 此时隐式遍历会走自定义逻辑 for (const i of demoArr) { console.log(i) // 依次输出 自定义内容1 自定义内容2 } // 手动调用values()方法,仍然按原有规则遍历值,不受重写影响 for (const i of demoArr.values()) { console.log(i) // 依次输出 x y z }
内容的提问来源于stack exchange,提问作者Ivan
相关产品推荐
相关产品推荐

