我可以通过将普通对象的原型设置为array.prototype
:
const obj = {};
Reflect.setPrototypeOf(obj, Array.prototype);
(我知道神奇的length
属性和稀疏数组也存在一些问题,但这不是这个问题的重点。)
我想使array.isArray(obj)
返回true
(当然不修改array.isArray()
方法)。 Array.IsArray()
的MDN 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()
或任何其他内置对象。
这与您可以用用户定义的对象伪装Array.isArray()基本相同,但这个问题是5年前提出的,答案是基于ECMAScript5规范的。 我正在寻找一个基于ECMAScript 2017规范的答案。
不,正如您已经说过的,一个真正的数组(也就是array.isArray
检测到的)是一个数组外来对象,这意味着它的.length
以一种特殊的方式运行。
唯一的构造方法是使用数组构造函数或array
的子类(它反过来调用数组构造函数),或者从另一个领域使用相同的方法。 还有无数其他方法返回新数组(例如String::Split
,String::Match
,Array.From
,Array.of
,Array.of
,Array
原型方法,Object.Key
,Object.GetOwnPropertyNames
)。
此外,用于标记模板或作为代理应用/构造陷阱的函数将接收全新的数组,并且数组也被构造为
如果您正在寻找创建数组的语法方法,那么array literal将是您的主要选择,但是析构表达式(在array literal或函数中)也可以从迭代器创建数组。
如果您的实际问题是“我能把一个任意对象变成一个数组奇异对象吗?”,答案是肯定的“否”。
一个对象被创建为一个奇异数组或者不是,你不能改变它。
但是,正如您所提到的,您可以创建一个目标是数组的代理对象。
null
console.log(Array.isArray(new Proxy([], {}))) // true
Babel可以将类MyObject extends Array
转换为ES5代码,从而使Array.IsArray(new MyObject)
返回true
:现场演示
class MyObject extends Array{};
console.log(Array.isArray(new MyObject))
"use strict";
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError(
"this hasn't been initialised - super() hasn't been called"
);
}
return call && (typeof call === "object" || typeof call === "function")
? call
: self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError(
"Super expression must either be null or a function, not " +
typeof superClass
);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass)
Object.setPrototypeOf
? Object.setPrototypeOf(subClass, superClass)
: (subClass.__proto__ = superClass);
}
var MyObject = (function(_Array) {
_inherits(MyObject, _Array);
function MyObject() {
return _possibleConstructorReturn(
this,
(MyObject.__proto__ || Object.getPrototypeOf(MyObject))
.apply(this, arguments)
);
}
return MyObject;
})(Array);
console.log(Array.isArray(new MyObject()));