有没有办法将现有的Javascript对象转换为数组而不创建新的单独数组?

Sma*_*Gal 9 javascript arrays object

在differentes读数上有很多提及数组是Javascript中特殊的对象类.例如这里:

https://www.codingame.com/playgrounds/6181/javascript-arrays---tips-tricks-and-examples

所以,由于objecta是属性(或键)和值的集合,我在想是否有一种方法可以从一个对象开始并以一个数组结束(从某种意义上说,该方法Array.isArray()返回true该对象模拟一个数组) .我已经开始查看数组属性:

let arr = [0, 1, 2, 3, 4, 5];
console.log(Object.getOwnPropertyNames(arr));
console.log(Array.isArray(arr));
Run Code Online (Sandbox Code Playgroud)

所以我尝试使用一个对象来模拟相同的东西:

let arrEmulation = {0:0, 1:1, 2:2, 3:3, 4:4, 5:5, "length":6};
console.log(Object.getOwnPropertyNames(arrEmulation));
console.log(Array.isArray(arrEmulation));
Run Code Online (Sandbox Code Playgroud)

Array.isArray(arrEmulation)仍然回归false.首先,我想道歉,如果这是一个愚蠢的问题,但有没有办法我可以手动转换objectarray添加特殊属性(或键)

请注意,我不想知道如何将对象转换为数组,我只想了解哪些特殊的东西可以解释像数组这样的对象.

Cer*_*nce 7

从严格意义上讲,鉴于标准规范,我认为这是不可能的.查找Array.isArray:

如果arg的[[Class]]内部属性的值是"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设置的原型arrEmulationArray.prototype,让您使用的对象数组的方法和有instanceof Array回报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));
Run Code Online (Sandbox Code Playgroud)

但要注意的是,你应该避免使用Object.setPrototypeOf在真正的代码:

警告:[[Prototype]]根据现代JavaScript引擎优化属性访问的性质,在每个浏览器和JavaScript引擎中,更改对象的速度非常慢.对改变继承的性能的影响是微妙和遥远的,并不仅仅局限于在Object.setPrototypeOf(...)语句中花费的时间,而是可以扩展到任何可以访问任何[[Prototype]]已被更改的对象的代码.如果您关心性能,则应避免设置[[Prototype]]对象.而是[[Prototype]]使用所需的使用创建一个新对象Object.create().

(当然,Object.create涉及创建一个对象,它与您想要做的不同,即更改现有arrEmulation对象)

在ES6 +中也没有办法做到这一点 - 它的文字有点类似,但不完全相同.具体来说,Array.isArray要返回true,有问题的对象需要是一个"异常对象"(或Proxy指向一个对象) - 但setPrototypeOf只设置原型,它或任何其他方法都不能使对象实际成为一个异常对象(看起来它必须由解释器本地构建,并且不能足够模拟).