非数组的cursor变量为何能使用forEach方法?
为什么非数组对象也能调用
forEach方法? 嘿,这个问题问得特别到位!很多初学者都会陷入「只有数组才能用forEach」的误区,其实这两者之间并没有强制绑定的关系,咱们来理清楚背后的逻辑:
核心原因:forEach 不是数组的专属方法
Array.prototype.forEach 确实是数组原型上的方法,但JavaScript的规则是:只要一个对象(不管是不是数组)本身或者原型链上存在forEach方法,它就能调用这个方法,和它是不是数组没有直接关系。
下面是几种常见的场景:
1. 内置的类数组对象
很多浏览器内置的类数组对象(不是数组,但结构类似数组)自带了forEach方法,比如:
NodeList(通过document.querySelectorAll()返回的DOM元素集合)HTMLCollection(比如document.getElementsByTagName()的返回值)
举个例子:
const divs = document.querySelectorAll('div'); console.log(Array.isArray(divs)); // 输出false divs.forEach(div => console.log(div)); // 正常遍历所有div元素
这类对象本质上不是数组,但浏览器为了方便开发者操作,给它们添加了forEach方法。
2. 手动添加forEach的类数组对象
你也可以自己创建一个类数组对象,然后把数组的forEach方法“借”过来用:
const cursor = { 0: 'item1', 1: 'item2', length: 2, // 直接复用数组的forEach方法 forEach: Array.prototype.forEach }; console.log(Array.isArray(cursor)); // false cursor.forEach(item => console.log(item)); // 输出item1、item2
这里cursor满足类数组的结构(有数字下标和length属性),加上我们给它绑定了数组的forEach,所以就能正常调用。
3. 自定义forEach方法的普通对象
有些对象会自己实现forEach逻辑,完全和数组无关:
const cursor = { tasks: ['吃饭', '睡觉', '写代码'], forEach(callback) { // 内部遍历自己的tasks数组,把回调传进去 this.tasks.forEach(callback); } }; console.log(Array.isArray(cursor)); // false cursor.forEach(task => console.log(task)); // 输出三个任务
这种情况下,cursor只是一个普通对象,但因为它自己定义了forEach方法,所以自然能调用。
4. 原型链继承了forEach的对象
如果某个对象的原型链上存在forEach方法,哪怕它本身不是数组,也能调用:
// 自定义一个构造函数 function CustomObj() {} // 把数组的forEach挂载到它的原型上 CustomObj.prototype.forEach = Array.prototype.forEach; const cursor = new CustomObj(); console.log(Array.isArray(cursor)); // false // 虽然这里cursor没有数组元素,但方法本身是可以调用的(只是遍历不到内容) cursor.forEach(item => console.log(item));
总结
Array.isArray() 只负责判断一个值是否是Array构造函数创建的实例,而forEach的调用条件仅仅是对象拥有这个方法(自身或原型链上)。这两者的判断逻辑完全独立,所以就会出现非数组对象能调用forEach的情况啦。
内容的提问来源于stack exchange,提问作者Osiris
相关产品推荐
相关产品推荐

