【问题标题】:Javascript Array behaving in a different mannerJavascript Array 以不同的方式表现
【发布时间】:2018-05-06 13:20:14
【问题描述】:

您好,我附上了我的 Firefox 控制台的屏幕截图,想知道为什么数组在 javascript 中的行为如此。

我试图理解 js 中的 for...in 和 for...of,但遇到了这个问题。我现在明白 for...in 只是打印键,而 for...of 是打印值部分。但是我不明白为什么数组首先取键值对?

我想由于 Array 也是一个对象,它可以将 A key:value 对作为输入,但是当我使用 console.log(a) 时,为什么它不打印 foo: bar,即使打印 a["foo" ]打印“酒吧”。是否有一些我错过并且无法理解的概念?

但是 Chrome 浏览器显示如下:

在这种情况下,打印数组 a 给我 [1,2,3,foo: "bar"] 作为输出但是如果我定义了

var b=[1,2,3,foo: "bar"] 

它给了我意想不到的令牌。为什么会这样?

【问题讨论】:

  • 因为你已经创建了一个"array like object"。数组具有数字索引,当您添加 a['foo'] 时,它会变成一个混合体。如果你不知道你在用 "array like object" 做什么,这不是一件好事
  • for...in 迭代可枚举属性,而 for...of 使用 Array 的 @@iteratorconsole.log 的输出只是浏览器/环境的选择。例如,Node.js 和 Chrome DevTools 将打印 [ 1, 2, 3, foo: 'bar' ]
  • @shinite 您可以在数组构造完成后向数组添加属性,但在此之前它必须是有效的语法
  • @shinite console.log 不一定会打印出有效的 JavaScript。它仅用于显示目的。但是,console.log( Object.assign( {}, a ) ); 会给你一个有效的对象。注意它不是一个数组。
  • 打印数组中的 foo:bar 很可能会有一个下拉箭头来展开并查看对象(在控制台中展开数组之后)。但是要将对象添加到数组中,不能只使用 foo:bar。对象需要包装在 {}

标签: javascript arrays object


【解决方案1】:

因为 Javascript 中的数组可以有成员(即数组中的内容),但也是对象,因此可以具有键/值属性。

这可能会让你有点困惑,所以让我们使用运输箱的比喻:

盒子里面有要运送的东西(成员),但它也有关于盒子本身的信息(送货地址、退货地址等......即属性)。然而,他们的 outside 上也有一个“运输清单”,其中详细说明了盒子 inside 的内容,这使得盒子的内容也是它的属性.

var box = [thing1ToShip, thing2ToShip]; // box contents
box.shippingAddress = 'some address'; // a box property (aka box['shippingAddress'])
box.returnAddress = 'some address'; // a box property (aka box['returnAddress'])
// The "manifest"
box[0] === thing1ToShip; // both content AND a box property
box[1] === thing2ToShip; // both content AND a box property
box.length === 2; // also a box property

For/of 循环遍历所提供对象的 iterable 属性,因此只返回数组本身中的值。这是因为 Javascript 中的对象可以定义它们应该如何迭代,而数组会根据 length 而不是键来定义它们自己的迭代。

For/in 循环遍历所提供对象的可枚举属性。因为数组的成员也是属性 (a[0]),所以您获得了您分配的键/值对和数组成员。

至于:

var b=[1,2,3,foo: "bar"]

它给了我意想不到的令牌。为什么会这样?

这仅仅是因为您正在编写无效的 Javascript。创建数组时无法定义其名称/值属性,只能定义其成员。要添加属性,您必须在创建数组之后执行此操作(使用正确的 [thing1, thing2, thing3] 语法)。

如果您想简洁地将属性添加到新数组中,您可以使用Object.assign

var b = Object.assign([1,2,3], {foo: "bar"});

换句话说,首先创建一个数组[1,2,3],然后将第二个参数 ({foo: "bar"}) 的属性分配给它……因为该对象中只有一个属性相当于“添加一个@ 987654335@" 属性添加到数组中。

【讨论】:

    【解决方案2】:

    这是一个很好的问题 :-) 粗略地说,数组是一个具有length 属性、一组从0length - 1 标记的属性以及几个特定功能的对象。我们几乎可以说a = [1, 2, 3] 是一个快捷方式:

    a = { 0: 1, 1: 2, 2: 3, length: 3 }
    

    实际上,您可以使用普通对象轻松模拟数组。

    对象是键值对的集合,就像字典一样。键可以是任意字符串,值可以是任何类型的数据。在 JavaScript 中,几乎所有东西都是对象。数组是对象,函数是对象,甚至像数字和字符串这样的原子数据也可以像对象一样被操作,事实上,JavaScript 会秘密地创建一个对象来包装原子数据。

    有几种方法可以创建对象。通常你会看到基于括号的文字符号({}[])或new 关键字。字面符号只是语法糖,实际上,您的计算机在两种情况下都执行完全相同的指令序列。也就是说,o = {}o = new Object() 相同,a = []a = new Array() 相同。

    是的,当您编写 a = [] 时,您正在隐式创建 Array 类的实例,这就是使数组成为特殊对象的原因 :-) 如上所述,数组是具有附加功能的对象,这些特性是从Array 类继承而来的。 indexOf 方法就是其中之一(在控制台中输入 Array.prototype 以将它们全部列出):

    var a = ["a", "b", "c"];
    a.indexOf("b"); // 1
    

    直到最近,只要您不从对象本身调用Array 特定方法,您就可以通过将length 属性添加到普通对象并将其用作数组来轻松欺骗JavaScript。 JQuery 利用了这种技术:http://api.jquery.com/Types/#ArrayLikeObject

    var o = { length: 0 };
    Array.prototype.push.call(o, "a", "b");
    console.log(o, Array.prototype.slice.call(o));

    今天这有点难以实现,例如,您必须实现一个迭代器才能在 for ... of 循环中使用普通对象:

    var o = {
      0: "a", 
      1: "b", 
      2: "c", 
      length: 3 
    };
    
    // o[Symbol.iterator] = Array.prototype[Symbol.iterator];
    // works as well, but I want you to see there is no magic :-)
    
    o[Symbol.iterator] = function() {
      return {
        i: 0,
        o: this,
        next: function() {
          var o = this.o;
          var i = this.i++;
          return {
            value: o[i],
            done: i === o.length
          }
        }
      };
    };
    
    for (var x of o) {
      console.log(x);
    }
    
    for (var x in o) {
      console.log(x, o[x]);
    }

    请注意,JavaScript 会忽略 for ... in 循环中真实数组的 length 属性。在我看来,这是一个有问题的选择,最有可能导致坦率新手的大脑出现蓝屏......

    var a = [1, 2, 3];
    a["i'm"] = "your father";
    
    console.log("length", a.length);
    for (var k in a) {
      console.log(k, a[k]);
    }

    最后,不要对 Chrome 控制台的输出感到困惑,它显示数组的方式是 Google 开发人员的任意选择。看,打印东西跟写源代码没关系,确实,你有这个权力!

    printArray([1, 2, 3]);
    
    function printArray(a) {
      console.log("[" 
      + a.join(", ") + ", "
      + "length: " + a.length 
      + "]");
    }

    进一步阅读:https://stackoverflow.com/a/5048482/1636522

    【讨论】:

      猜你喜欢
      • 2014-01-25
      • 1970-01-01
      • 1970-01-01
      • 2014-04-05
      • 2018-03-21
      • 1970-01-01
      • 2014-11-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多