【问题标题】:Javascript array becomes an object structureJavascript数组变成对象结构
【发布时间】:2012-05-02 09:00:04
【问题描述】:

我在使用包含一些对象的 javascript 数组时遇到了一种奇怪的行为(也许这根本不奇怪,只是我不明白为什么)。

由于我不是 javascript 专业人士,因此很可能会清楚地解释为什么会发生这种情况,我只是不知道。

我有在文档中运行的 javascript。它创建了一个类似这样的对象数组:

var myArray = [{"Id":"guid1","Name":"name1"},{"Id":"guid2","Name":"name2"},...];

如果我像 JSON.stringify(myArray) 这样在创建它的地方打印出这个数组,我会得到我所期望的:

[{"Id":"guid1","Name":"name1"},{"Id":"guid2","Name":"name2"},...]

但是,如果我尝试从子文档访问此数组到此文档(由第一个文档打开的窗口中的文档),则该数组不再是数组。 所以在子文档中做 JSON.stringify(parent.opener.myArray) 会产生如下结果:

{"0":{"Id":"guid1","Name":"name1"},"1":{"Id":"guid2","Name":"name2"},...}

这不是我所期望的 - 我期望得到与我在父文档中所做的相同的结果。

谁能向我解释为什么会发生这种情况以及如何修复它以使该数组在从子窗口/文档寻址时仍然是一个数组?

PS。对象并没有像上面所说的那样添加到数组中,它们是这样添加的:

function objTemp()
{
    this.Id = '';
    this.Name = '';
};

var myArray = [];

var obj = new ObjTemp();
obj.Id = 'guid1';
obj.Name = 'name1';

myArray[myArray.length] = obj;

如果这有什么不同的话。

任何帮助都将不胜感激,既可以解决我的问题,也可以更好地了解正在发生的事情:)

【问题讨论】:

  • 你在什么浏览器上测试?我记得有一个线程在 IE 中发生了完全相同的行为,但在 FF 中没有。你能提供一个 JSFiddle 来测试这个问题吗?见here
  • 我无法复制。你在哪个浏览器中测试过?你用过 JSON 库吗?
  • 我在 IE 中进行测试,因为这是一项要求。就个人而言,我不会选择 IE,但这不取决于我。在此示例中,我仅使用 json 来对警报进行字符串化。我没有为产生该行为的代码使用任何 json 库。
  • 如果我在创建数组的文档中执行 alert(typeof myArray.sort),我会得到“函数”。如果我在子文档中执行 alert(typeof parent.opener.myArray.sort) 我会得到“对象”,是的,这是 IE。看起来这与您链接的帖子中的情况完全相同。那么该怎么办呢?另一篇文章没有提供答案或解决方案。
  • 不要使用 IE :-) Object.prototype.toString.apply(value) === '[object Array]' 的数组检测是否有效?然后,您可以使用使用此方法的 JSON 库。

标签: javascript arrays object


【解决方案1】:

最后一行可能导致问题,您是否尝试将myArray[myArray.length] = obj; 替换为myArray.push(obj);?可能是这样,因为你明确地创建了一个新索引,所以数组变成了一个对象......虽然我只是在这里猜测。你能添加检索myArray的子文档使用的代码吗?

编辑

忽略上面的,因为它不会有任何区别。不过,不想吹嘘,我的想法是正确的。我的想法是,通过仅使用专有数组方法,解释器会将其视为myArray 类型的线索。问题是:myArray 一个数组,就父文档而言,但是由于您将数组从一个文档传递到另一个文档,所以会发生以下情况:

数组是一个对象,具有自己的原型和方法。通过将它传递给另一个文档,您将整个 Array 对象(值和原型)作为一个对象传递给子文档。在文档之间传递变量时,您实际上是在创建变量的副本(JavaScript 唯一一次复制 var 的值)。由于数组是一个对象,它的所有属性(和原型方法/属性)都被复制到Object 对象的“无名”实例中。类似于var copy = new Object(toCopy.constructor(toCopy.valueOf())); 的事情正在发生……解决这个问题的最简单方法,IMO,是使用父上下文对数组进行严格处理,因为在那里,解释器知道它是一个数组:

//parent document
function getTheArray(){ return JSON.stringify(myArray);}
//child document:
myArray = JSON.parse(parent.getTheArray());

在此示例中,var 在仍将 myArray 视为真正的 JavaScript 数组的上下文中进行字符串化,因此生成的字符串将是您所期望的。在将 JSON 编码字符串从一个文档传递到另一个文档时,它将保持不变,因此 JSON.parse() 将为您提供 myArray 变量的精确副本。

请注意,这只是黑暗中的又一次野蛮刺伤,但我现在已经考虑了更多。如果我对此有误,请随时纠正我......我总是很高兴学习。如果这是真的,也请告诉我,因为这无疑迟早会成为我的陷阱

【讨论】:

  • 不,该语法对于创建数组的新成员是完全有效的。虽然 .push() 更具描述性(我更喜欢它),但分配也有效,甚至更快。
  • 我不认为数组是无效的,因为我向它添加项目的方式,正如我在帖子中所说的那样,如果我尝试提醒数组字符串化它看起来是正确的(又名它是不是一个对象,而是一个数组)。如果我从子文档中执行完全相同的操作,则数组现在是一个对象,不仅在我警告 var stringified 时,而且应该与数组一起使用的代码会引发错误,因为例如myArray[0].Id 为空(因为它不存在的原因)。
  • 在父页面上对数组进行字符串化,然后在子页面上解析字符串就可以了,感谢您相当彻底的回答,我也学到了一些东西:)
  • 就我而言,用.[i] = x 替换.push(x) 实际上确实保留了.slice 方法。而使用 stringify 在 localhost:1 O_o 上给了我一个奇怪的unexpected token A
  • 6 年后,我仍然偶然发现了这一点。使用 ECMA 6,还有其他选择吗?
【解决方案2】:

查看本文末尾http://www.karmagination.com/blog/2009/07/29/javascript-kung-fu-object-array-and-literals/,了解此行为的示例和解释。

基本上归结为 Array 是一种原生类型,并且每个框架都有自己的一组原生对象和变量。

来自文章:

// in parent window
var a = [];
var b = {};
//inside the iframe
console.log(parent.window.a); // returns array
console.log(parent.window.b); // returns object

alert(parent.window.a instanceof Array); // false
alert(parent.window.b instanceof Object); // false
alert(parent.window.a.constructor === Array); // false
alert(parent.window.b.constructor === Object); // false

您对 JSON.stringify 的调用实际上执行了以下检查(来自 json.js 源),这似乎未能将其指定为数组:

        // Is the value an array?
        if (Object.prototype.toString.apply(value) === '[object Array]') {
           //stringify

【讨论】:

  • 不,似乎完全不使用 Array.isArray,它可以跨窗口工作,而是使用 instanceof 来导致所描述的行为。
  • 哦,是的,现在看起来它是特定于浏览器的,因为 json2.js 默认只执行浏览器的本机版本的 stringify,如果可用的话(它应该在所有现代浏览器中)
  • 我的意思是代码Object.prototype.toString.apply(value) === '[object Array]' 不会失败,尽管你这么说。
猜你喜欢
  • 2016-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-10
  • 2022-01-09
  • 1970-01-01
  • 1970-01-01
  • 2023-04-04
相关资源
最近更新 更多