通过将对象的原型设置为 Array.prototype
,我可以轻松地使一个普通对象看起来像一个数组:
const obj = {};
Reflect.setPrototypeOf(obj, Array.prototype);
(我知道魔法长度属性和稀疏数组也存在一些问题,但这不是本问题的重点。)
我想让
Array.isArray(obj)
返回true
(当然不能修改Array.isArray()
方法)。MDN关于Array.isArray()
的polyfill如下:
if (!Array.isArray) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}
通过使用 Symbol.toStringTag
属性,我可以使 Object.prototype.toString.call(obj)
返回 '[object Array]'
:obj[Symbol.toStringTag] = 'Array';
console.log(Object.prototype.toString.call(obj) === '[object Array]'); // true
现在,经过填充的
Array.isArray()
对于obj
返回true
(请忽略不支持Array.isArray()
的浏览器都不支持Symbol.toStringTag
的事实)。然而,本地Array.isArray()
函数仍然对obj
返回false
。我查看了ECMAScript 2017规范,它说Array.isArray()
使用抽象操作IsArray
,如果参数是一个数组奇异对象,则返回true
。如果参数是代理,则直接在目标对象上调用IsArray
,因此似乎在这里使用代理并没有帮助。
有没有办法使Array.isArray(obj)
返回true
?为了明确起见,我不想修改Array.isArray()
或任何其他内置对象。
这基本上与Can you fake out Array.isArray() with a user-defined object?相同,但该问题是5年前提出的,答案基于ECMAScript 5规范。我正在寻找基于ECMAScript 2017规范的答案。