为什么有些数组方法依赖于全局数组对象?

2022-07-03 00:00:00 arrays javascript prototype

我正在检查MDN docs on arrays,当我们想要测试一个对象是否为数组时,我们使用isArray()。然而,它的用法与大多数其他方法非常不同。使用常规语法时,会弹出错误:

console.log([1,2,3].isArray());  // TypeError: [1, 2, 3].isArray is not a function

鉴于这确实起作用:

console.log(Array.isArray([1,2,3]))

我不明白为什么isArray()(以及其他几个方法)依赖于某个全局对象,而不是仅仅通过所讨论的对象访问。为什么某些方法需要全局数组对象?


解决方案

而不仅仅是可以通过相关对象访问。

,因为Array.isArray的全部目的是在未知对象上调用。您不知道它是否是数组,也不知道该方法在它上是否可访问。静态方法甚至可以与null这样的值一起使用,当您尝试对它们调用方法时,这将不可避免地引发异常。


离题:

isArray作为实例方法可调用可以工作。在Smalltalk、Ruby或Io等一切都是对象的语言中,甚至像nil这样的东西也可以有isNil方法。当然,这种方法还有其他问题,因为使用动态方法分派时,每个任意对象都可能覆盖该方法并声明为数组--另一方面,这正是我们希望duck typing。

我们甚至可以使用Object.prototype.isArray = () => false;Array.prototype.isArray = () => true;在JS中模拟这一过程。除了在nullundefined上失败外,它仍然不能处理不是从(我们的领域)Object.prototype继承的对象。而混合了数据字段和方法的JavaScript"属性"也没有帮助(考虑一下从JSON字符串{"isArray":"maybe"}解析的对象)。我们总是必须预料到.isArray不是函数,或者它被抛出的方法覆盖时会出现异常。
如果我们想要在JS中进行鸭子类型,检查对象是否具有整型.length属性通常是可行的。或更高级,尝试遵循symbol-based iteration protocol。(例如,Array.from就是这样使用的)。


但是由于数组在JS中有点特殊(凭借其神奇的.length属性),我们需要一种内置的可靠方法来检测它们,这正是Array.isArray所做的。

关于其他静态Array方法:Array.of非常明显,它是工厂函数(类似于构造函数),而不能是实例方法,因为首先没有实例可用。对于Array.from,情况更像isArray,鸭子类型Object.prototype.toArray方法也同样有效,但由于实际和设计原因而被取消。

有关类似的讨论,请参阅Why were ES5 Object methods not added to Object.prototype?和Why is it Object.defineProperty() rather than this.defineProperty() (for objects)?。

相关文章