Я не думаю, что это возможно, в самом строгом смысле, учитывая стандартную спецификацию.Поиск Array.isArray :
Если значение внутреннего свойства [[Class]] для arg равно "Array", тогда вернуть true.
Таким образом, чтобы Array.isArray(arrEmulation)
вернул true
, вы должны как-то изменить [[Class]]
объекта, чтобы оно было Array
, а не Object
.Но, глядя на ES5 8.6.2. Внутренние свойства и методы объекта относительно [[Class]]
:
Примечание. Эта спецификация не определяет операторов языка ECMAScript или встроенных функций, которые разрешаютпрограмма для изменения внутренних свойств объекта [[Class]] или [[Prototype]] или для изменения значения [[Extensible]] с false на true.Специфичные для реализации расширения, которые изменяют [[Class]], [[Prototype]] или [[Extensible]], не должны нарушать инварианты, определенные в предыдущем абзаце.
Также:
Обратите внимание, что эта спецификация не предоставляет программам никаких средств для доступа к этому значению, кроме как через Object.prototype.toString
Итак, официальная спецификация не предоставляет способ сделать это в ES5 -если бы был способ сделать это, он был бы нестандартным и зависящим от реализации.
Тем не менее, если вам абсолютно не нужно для использования Array.isArray
илиесть Object.prototype.toString.call(arrEmulation)
для возврата [object Array]
, вы все равно можете использовать Object.setPrototypeOf
для установки прототипа arrEmulation
на Array.prototype
, что позволяет вам использовать методы массива для объекта и иметь instanceof Array
return true
:
const arrEmulation = {0:0, 1:1, 2:2, "length":6};
Object.setPrototypeOf(arrEmulation, Array.prototype);
console.log(arrEmulation instanceof Array);
arrEmulation.forEach((value) => {
console.log(value);
});
// Internal [[Class]] property is still `Object`, though:
console.log(Object.prototype.toString.call(arrEmulation));
// Unlike a true array:
console.log(Object.prototype.toString.call([]));
console.log('-----');
// although you can set the `toStringTag` to the string 'Array' in ES6+,
// it is cosmetic only and does not pass an `Array.isArray` test:
arrEmulation[Symbol.toStringTag] = 'Array';
console.log(Object.prototype.toString.call(arrEmulation));
console.log(Array.isArray(arrEmulation));
Но учтите, что вам следует избегать , используя Object.setPrototypeOf
в реальном коде:
Предупреждение: изменение [[Prototype]]
объект по природе того, как современные движки JavaScript оптимизируют доступ к свойствам, является очень медленной операцией в каждом браузере и движке JavaScript.Влияние изменения производительности наследования на тонкость и масштабность не ограничивается простым временем, затрачиваемым в операторе Object.setPrototypeOf(...)
, но может распространяться на любой код, который имеет доступ к любому объекту, чье [[Prototype]]
было изменено.Если вы заботитесь о производительности, вам следует избегать установки [[Prototype]]
объекта.Вместо этого создайте новый объект с желаемым [[Prototype]]
, используя Object.create()
.
(конечно, Object.create
предполагает создание нового объекта, который отличается от того, чтовы хотите сделать, то есть изменить существующий объект arrEmulation
)
В ES6 + также не существует способа сделать это - его текст чем-то похож ,но не идентичны.В частности, чтобы Array.isArray
возвратил true
, рассматриваемый объект должен быть «Массивом экзотического объекта» (или Proxy
, который указывает на единицу), но setPrototypeOf
устанавливает толькоПрототип, ни он, ни любой другой метод не могут сделать объект фактически превращенным в экзотический объект Array (который выглядит так, как будто он должен быть изначально создан интерпретатором, и не является достаточно эмулируемым).