有没有办法在不创建新的单独数组的情况下将现有的Javascript对象转换为数组? [英] Is there any way to turn an existing Javascript object into an array without creating a new separate array?

查看:73
本文介绍了有没有办法在不创建新的单独数组的情况下将现有的Javascript对象转换为数组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

关于差异阅读的内容有很多提及,其中数组是Javascript中的特殊对象类.例如此处:

There are a lot of mentions on differentes readings that arrays are a special class of object in Javascript. For example here:

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

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

So, and since an object is a collection of properties (or keys) and values, I was thinking if there is a way to start with an object and ends with an array (in the sense that the method Array.isArray() returns true for that object emulating an array). I have started looking at the arrays properties:

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

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

So I tried to emulate the same using an object:

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));

但是Array.isArray(arrEmulation)仍然返回false.首先,如果这是一个愚蠢的问题,我想道歉,但是有什么方法可以手动将object转换为array并添加特殊属性(或键)吗?

But Array.isArray(arrEmulation) still returns false. First, I want to apologize if this is an stupid question, but is there any way I can manually convert an object to array adding special properties (or keys) to it?

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

Please, note I don't want to know how to convert object to array, I just want to understand which are those special things that make possible to interpret an object like an array.

推荐答案

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

I don't think it's possible, in the strictest sense, given the standard specification. Looking up Array.isArray:

如果arg的[[Class]]内部属性的值为"Array",则返回true.

If the value of the [[Class]] internal property of arg is "Array", then return true.

因此,要使Array.isArray(arrEmulation)返回true,必须以某种方式将对象的[[Class]]修改为Array,而不是Object.但是,请查看ES5的 8.6.2对象内部属性和方法关于[[Class]]:

So, for Array.isArray(arrEmulation) to return true, you must somehow modify the [[Class]] of the object to be Array, rather than Object. But, looking at ES5's 8.6.2 Object Internal Properties and Methods regarding [[Class]]:

注意:本规范未定义任何ECMAScript语言运算符或内置函数,它们不允许程序修改对象的[[Class]]或[[Prototype]]内部属性或将[[Extensible]]的值更改为从虚假到真实.修改[[Class]],[[Prototype]]或[[Extensible]]的特定于实现的扩展不得违反上一段中定义的不变式.

Note: This specification defines no ECMAScript language operators or built-in functions that permit a program to modify an object’s [[Class]] or [[Prototype]] internal properties or to change the value of [[Extensible]] from false to true. Implementation specific extensions that modify [[Class]], [[Prototype]] or [[Extensible]] must not violate the invariants defined in the preceding paragraph.

也:

请注意,除非通过Object.prototype.toString

因此,官方规范没有在ES5中提供执行此操作的方法-如果有 执行操作的方法,则它将是非标准的且取决于实现.

So, the official specification doesn't provide a way to do it in ES5 - if there was a way to do it, it would be non-standard and implementation dependent.

也就是说,除非您绝对需要使用Array.isArray或让Object.prototype.toString.call(arrEmulation)返回[object Array],否则您仍然可以使用Object.setPrototypeOfarrEmulation的原型设置为Array.prototype,允许您在对象上使用数组方法并使instanceof Array返回true:

That said, unless you absolutely need to use Array.isArray or have Object.prototype.toString.call(arrEmulation) to return [object Array], you can still use Object.setPrototypeOf to set the prototype of arrEmulation to Array.prototype, allowing you to use array methods on the object and have 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:

But note that you should avoid using Object.setPrototypeOf in real code:

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

Warning: Changing the [[Prototype]] of an object is, by the nature of how modern JavaScript engines optimize property accesses, a very slow operation, in every browser and JavaScript engine. The effects on performance of altering inheritance are subtle and far-flung, and are not limited to simply the time spent in the Object.setPrototypeOf(...) statement, but may extend to any code that has access to any object whose [[Prototype]] has been altered. If you care about performance you should avoid setting the [[Prototype]] of an object. Instead, create a new object with the desired [[Prototype]] using Object.create().

(当然,Object.create涉及创建一个 new 对象,该对象不同于您要执行的操作,即更改现有的arrEmulation对象)

(of course, Object.create involves creating a new object, which is different from what you want to do, which is to change the existing arrEmulation object)

在ES6 +中也似乎没有一种方法可以实现-它的文本有点相似,但不完全相同.具体来说,为了使Array.isArray返回true,所讨论的对象需要是数组奇异对象"(或指向一个对象的Proxy)-但是setPrototypeOf仅设置原型,它或任何其他方法都不能使对象实际上成为一个Array奇异对象(看起来它必须由解释器本地构造,并且不能充分仿真).

There doesn't look to be a way to do it in ES6+ either - its text is somewhat similar, but not identical. Specifically, for Array.isArray to return true, the object in question needs to be an "Array exotic object" (or a Proxy that points to one) - but setPrototypeOf only sets the prototype, neither it nor any other method can make the object actually become an Array exotic object (which looks like it has to be natively constructed by the interpreter, and is not emulatable enough).

这篇关于有没有办法在不创建新的单独数组的情况下将现有的Javascript对象转换为数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆