【问题标题】:Is array both associative and indexed?数组是关联的还是索引的?
【发布时间】:2010-11-07 18:42:44
【问题描述】:

JavaScript 中的数组可以关联和索引吗?

我希望能够通过位置或键值在数组中查找项目。

【问题讨论】:

  • 这已经很老了,但是你可以使用 Object.keys(array) 来按顺序获取键
  • 你是 PH​​P 程序员 :)

标签: javascript arrays indexing associative


【解决方案1】:

对象在关联 javascript 数组中出现的顺序没有定义,并且在不同的实现中会有所不同。因此,您不能真正指望给定的关联键始终位于同一索引处。

编辑:

正如 Perspx 所指出的,javascript 中并没有真正的关联数组。声明foo["bar"] 只是foo.bar 的语法糖

如果你相信浏览器会维护对象中元素的顺序,你可以编写一个函数

function valueForIndex(obj, index) {

    var i = 0;
    for (var key in obj) {

        if (i++ == index)
            return obj[key];
    }
}

【讨论】:

  • 虽然这是真的,但实际上所有主流浏览器都会按照对象的定义顺序循环遍历对象的属性。当然,这不在规范中,但值得一提。
  • JavaScript 没有关联数组。你的答案是在谈论对象,而不是数组。
【解决方案2】:

Javascript 中没有关联数组之类的东西。您可以使用对象字面量,它看起来 像关联数组,但它们具有无序属性。常规 Javascript 数组基于整数索引,不能关联。

例如,对于这个对象:

var params = {
    foo: 1,
    bar: 0,
    other: 2
};

您可以从对象中访问属性,例如:

params["foo"];

您还可以使用for...in 语句遍历对象:

for(var v in params) {
    //v is equal to the currently iterated property
}

但是,对于属性迭代的顺序没有严格的规定 - 对象字面量的两次迭代可能会以不同的顺序返回属性。

【讨论】:

  • 实际上,JavaScript 数组也可以有非整数索引。它只是没有太多处理它们的方法。
  • 你的意思是像一个字符串?在这种情况下,它不是一个数组,只是一个具有属性的对象。
  • Nosredna:JS 数组没有键索引,那些 JS 对象被认为是对象字面量。所以: foo["bar"] = 1; foo.bar === foo["bar"]; //true foo["bar"] === foo[0]; //false 这是关于 JS 的许多微妙的怪癖之一,很容易让人失望。
  • JavaScript 对象,包括数组,只有 字符串索引。 a[1] 实际上是在说 a['1']
  • 最新的 MDN 文档清楚地表明数组索引必须是整数。 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
【解决方案3】:

在阅读了Wikipedia definition of associative array 之后,我将打破传统的 JavaScript 知识并说:“是的,JavaScript 确实有关联数组。”使用 JavaScript 数组,您可以通过它们的键添加、重新分配、删除和查找值(键可以是带引号的字符串),这就是维基百科所说的关联数组应该能够做到的。

但是,您似乎在问一些不同的问题——您是否可以通过索引或键查找相同的值。这不是关联数组的要求(请参阅 Wikipedia 文章。)关联数组不必让您能够通过索引获取值。

JavaScript arrays are very closely akin to JavaScript objects.

  arr=[];
  arr[0]="zero";
  arr[1]="one";
  arr[2]="two";
  arr["fancy"]="what?";

是的,这是一个数组,是的,您可以摆脱非数字索引。 (如果你好奇,毕竟 arr.length 是 3。)

在大多数情况下,我认为在使用数组时应该坚持使用数字索引。我认为这正是大多数程序员所期望的。

链接是我关于该主题的博客文章。

【讨论】:

  • 当你说“你可以有一个非数字索引的数组”时你是对的。它不知何故让我忘记了,但我知道这个事实。
  • 学究起来,“fancy”不是数组中的索引,而是数组实例对象的一个​​属性。
  • @BaroqueBobcat: 真的很迂腐:) 数组中的索引只是数组实例对象的属性(“属性”);数组只是特别对待那些与长度属性有关的整数的字符串形式的属性。
  • 一点也不迂腐。这是一个非常重要的区别,当您开始尝试将数组序列化为 JSON 时,这一点就很明显了。具有非数字键的值 不是 数组数据的一部分。 (严格来说,你不使用.push() 会破坏你的数组。)
  • 我对这个答案投了反对票,因为虽然可以使用看起来像数组的语法,但这不是正确的 javascript 也不是正确的数组。您的答案很适合参考,但应该明确提醒您这不是您通常使用数组的方式。
【解决方案4】:

原生JS对象只接受字符串作为属性名,这是真的even for numeric array indices;数组与普通对象的不同之处仅在于大多数 JS 实现将以不同的方式存储数字索引的属性(即,只要它们是密集的,就在实际数组中)并且设置它们将触发额外的操作(例如调整 length 属性)。

如果您正在寻找接受任意键的映射,则必须使用non-native implementation。该脚本旨在用于快速迭代,而不是通过数字索引进行随机访问,因此它可能也不是您想要的。

可以执行您要求的地图的准系统实现可能如下所示:

function Map() {
    this.length = 0;
    this.store = {};
}

Map.prototype.get = function(key) {
    return this.store.hasOwnProperty(key) ?
        this.store[key] : undefined;
};

Map.prototype.put = function(key, value, index) {
    if(arguments.length < 3) {
        if(this.store.hasOwnProperty(key)) {
            this.store[key].value = value;
            return this;
        }

        index = this.length;
    }
    else if(index >>> 0 !== index || index >= 0xffffffff)
        throw new Error('illegal index argument');

    if(index >= this.length)
        this.length = index + 1;

    this[index] = this.store[key] =
        { index : index, key : key, value : value };

    return this;
};

put()index 参数是可选的。

您可以通过键或索引访问映射 map 中的值

map.get('key').value
map[2].value

【讨论】:

  • +1,但我会失去“数字索引的属性将以不同的方式存储”:情况不一定如此,规范也不需要。
  • 你怎么放? map.put('key','value') 和 map[2].value = val ?
  • map.put('key','value') 用于附加值,map.put('key','value', 42) 用于在给定位置插入值; map[42].value = 'value' 也可以使用(即替换现有键值对的值),但您无法更改条目的键或索引或以这种方式添加新条目
【解决方案5】:
var stuff = [];
stuff[0] = "foo";
stuff.bar = stuff[0]; // stuff.bar can be stuff["bar"] if you prefer
var key = "bar";
alert(stuff[0] + ", " + stuff[key]); // shows "foo, foo"

【讨论】:

  • 但是自从你添加了 .bar 之后,stuff.length 就不再是 1 了,对吧?因此按索引循环将不再起作用..
  • 否 - 添加命名属性不会增加长度;仅通过数字索引添加元素会增加长度。添加“stuff[1000] = 'blah'”会导致长度增加到 1001,即使实际上只添加了两个数字索引元素和一个命名属性。不是很有趣;-)
【解决方案6】:

是的。

test = new Array();
test[0] = 'yellow';
test['banana'] = 0;
alert(test[test['banana']]);

【讨论】:

    【解决方案7】:

    虽然我同意给出的答案,但您实际上可以使用 getter 和 setter 完成您所说的。例如:

    var a = [1];
    //This makes a["blah"] refer to a[0]
    a.__defineGetter__("blah", function(){return this[0]});
    //This makes a["blah"] = 5 actually store 5 into a[0]
    a.__defineSetter__("blah", function(val){ this[0] = val});
    
    alert(a["blah"]); // emits 1
    a["blah"] = 5;
    alert(a[0]); // emits 5
    

    这就是你要找的吗?我认为有一种不同的更现代的方法来做 getter 和 setter,但不记得了。

    【讨论】:

    • 哦,如果你要在循环中执行此操作,你可能需要关闭 btw... 只是说。
    【解决方案8】:
    var myArray = Array();
    myArray["first"] = "Object1";
    myArray["second"] = "Object2";
    myArray["third"] = "Object3";
    
    Object.keys(myArray);              // returns ["first", "second", "third"]
    Object.keys(myArray).length;       // returns 3
    

    如果你想要第一个元素,那么你可以像这样使用它:

    myArray[Object.keys(myArray)[0]];  // returns "Object1"
    

    【讨论】:

      【解决方案9】:

      我来这里是想知道这是否是不好的做法,结果发现很多人似乎不理解这个问题。

      我想要一个有序但可以通过键索引的数据结构,这样就不需要每次查找都进行迭代。

      实际上,这很简单,但我仍然没有读到任何关于这是否是一种糟糕的做法。

      var roygbiv = [];
      var colour = { key : "red", hex : "#FF0000" };
      roygbiv.push(colour);
      roygbiv[colour.key] = colour;
      ...
      console.log("Hex colours of the rainbow in order:");
      for (var i = 0; i < roygbiv.length; i++) {
          console.log(roygbiv[i].key + " is " + roygbiv[i].hex);
      }
      
      // input = "red";
      console.log("Hex code of input colour:");
      console.log(roygbiv[input].hex);
      

      重要的是永远不要在对象设置后直接更改array[index] 或array[key] 的值,否则这些值将不再匹配。如果数组包含对象,您可以更改这些对象的属性,并且您将能够通过任一方法访问更改后的属性。

      【讨论】:

      • 这是我采用的方法,但语法显示了分配时的关联,我发现它更符合我的喜好aSignals[aSignals.length] = aSignals['fooBar'] = { 'sKey': 'foobBar', ... }
      【解决方案10】:

      这一趋势已经改变。现在你可以做到了……还有更多!使用 Harmony Proxies,您绝对可以通过多种方式解决这个问题。

      您必须在 harmony-reflect shim 的帮助下验证您的目标环境是否支持此功能。

      在 Mozilla 开发者网络上有一个非常好的例子,它使用代理到 ​​find an array item object by it's property 几乎可以概括。

      这是我的版本:

        var players = new Proxy(
        [{
          name: 'monkey',
          score: 50
        }, {
          name: 'giraffe',
          score: 100
        }, {
          name: 'pelican',
          score: 150
        }], {
          get: function(obj, prop) {
            if (prop in obj) {
              // default behavior
              return obj[prop];
            }
            if (typeof prop == 'string') {
      
              if (prop == 'rank') {
                return obj.sort(function(a, b) {
                  return a.score > b.score ? -1 : 1;
                });
              }
      
              if (prop == 'revrank') {
                return obj.sort(function(a, b) {
                  return a.score < b.score ? -1 : 1;
                });
              }
      
              var winner;
              var score = 0;
              for (var i = 0; i < obj.length; i++) {
                var player = obj[i];
                if (player.name == prop) {
                  return player;
                } else if (player.score > score) {
                  score = player.score;
                  winner = player;
                }
              }
      
              if (prop == 'winner') {
                return winner;
              }
              return;
            }
      
          }
        });
      
        console.log(players[0]); // { name: 'monkey', score: 50 }
        console.log(players['monkey']); // { name: 'monkey', score: 50 }
        console.log(players['zebra']); // undefined
        console.log(players.rank); // [ { name: 'pelican', score: 150 },{ name: 'giraffe', score: 100 }, { name: 'monkey', score: 50 } ]
        console.log(players.revrank); // [ { name: 'monkey', score: 50 },{ name: 'giraffe', score: 100 },{ name: 'pelican', score: 150 } ]
        console.log(players.winner); // { name: 'pelican', score: 150 }
      

      【讨论】:

        【解决方案11】:

        最新的 MDN 文档清楚地表明数组索引必须是整数。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array

        let arr=[];
         arr[0]="zero";
         arr[1]="one";
         arr[2]="two";
         arr["fancy"]="what?";
        
        //Arrays cannot use strings as element indexes (as in an associative array) but must use integers. 
        //Setting non-integers using bracket notation will not set an element to the Array List itself
        //A non-integer will set a variable associated with that ARRAY Object property collection 
        let denseKeys = [...arr.keys()];
        console.log(denseKeys);//[ 0, 1, 2 ]
        console.log("ARRAY Keys:"+denseKeys.length);//3
        
        
        let sparseKeys = Object.keys(arr);
        console.log(sparseKeys);//[ '0', '1', '2', 'fancy' ]
        console.log("Object Keys:"+sparseKeys.length);//4
        
        const iterator = arr.keys();
        for (const key of iterator) {
          console.log(key);//0,1,2
        }
        

        【讨论】:

          猜你喜欢
          • 2010-11-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-07-25
          • 2014-09-30
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多