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

时间:2019-02-05 03:49:10

标签: javascript arrays object

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

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

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

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

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

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并为其添加特殊属性(或键)

  

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

>

3 个答案:

答案 0 :(得分:6)

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

  

如果arg的[[Class]]内部属性的值为“ Array”,则返回true。

因此,为了使Array.isArray(arrEmulation)返回true,您必须以某种方式将对象的[[Class]]修改为Array,而不是Object。但是,请查看ES5关于[[Class]]的{​​{3}}:

  

注意:本规范未定义任何ECMAScript语言运算符或内置函数,这些运算符或内置函数不允许程序修改对象的[[Class]]或[[Prototype]]内部属性或将[[Extensible]]的值更改为从虚假到真实。修改[[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));

但是请注意,您应该8.6.2 Object Internal Properties and Methods在真实代码中使用Object.setPrototypeOf

  

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

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

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

答案 1 :(得分:2)

Javascript全部涉及原型继承:

  

Prototype Inheritance   所有JavaScript对象都从   原型:

     

日期对象继承自Date.prototype数组对象继承自Date   Array.prototype Person对象继承自Person.prototype   Object.prototype位于原型继承链的顶部:

     

日期对象,数组对象和Person对象继承自   Object.prototype。

如此处所示,isArray是Array对象原型链中的一个函数。

如果MDN Array.isArray()中不存在isArray,则建议使用polyfill:

if (!Array.isArray) {
  Array.isArray = function(arg) {
    return Object.prototype.toString.call(arg) === '[object Array]';
  };
}

所以类型是由原型链决定的,而不是它返回什么值。

  

类似地,根据Tio Zed的回答

const newArray = Array.from(arrEmulation) // [0, 1, 2, 3, 4, 5]
Array.isArray(newArray)

它的真正作用是将原型从对象的原型更改为数组的原型。

isArray的更深入研究,感谢@Kaiido使我更深入。 数组是数组检查these there points

  

如果Type(arg)不是Object,则返回false。   如果arg的[[Class]]内部属性的值为“ Array”,   然后返回true。返回false。

And

  

Array实例从Array原型对象继承属性,并且   它们的[[Class]]内部属性值为“ Array”。阵列实例   也具有以下属性。

答案 2 :(得分:0)

您可以使用Array.from()转换与数组足够接近的任何内容。 在您的示例中,我们可以调用:

if(isset($_REQUEST["term"])){
// Prepare a select statement
$term = $_REQUEST['term'];

     $sql = "SELECT * FROM fresh  WHERE 
     description LIKE '%{$term}%' or 
     sku like '%{$term}%'
     union
     SELECT * FROM marine WHERE 
     description LIKE '%{$term}%' or 
     sku like '%{$term}%'";

        if($stmt = mysqli_prepare($link, $sql)){
        // Bind variables to the prepared statement as parameters
        mysqli_stmt_bind_param($stmt, "s", $param_term);

        // Set parameters
        $param_term = $_REQUEST["term"] . '%';