javascript - 将索引号分配给 JavaScript 对象键

标签 javascript

目标:最终目标是拥有一种访问有序列表中对象的数据以及在有序列表上调用排序或映射等方法的方法/技术。如果我可以为每个键值分配一个索引号,那么这应该是可能的。如果我们可以为对象的每个键值分配一个索引,那么其余的应该通过创建映射和排序的版本或继承 Array 对象来完成。

var foo = { 
  bar : 'value',
  foobar : 'value2'
};

//the magic here

foo.bar // 'value'
foo[0] // 'value' (This is the ideal solution it does not have to be this way)

问题:有没有办法将索引号分配给 JavaScript 对象键?

想法:我知道 JavaScript 对象是哈希表,因此它们有一个分配给它们的键,但它们是完全随机的,并且可能会随着您更改哈希表的大小而改变。所以那是行不通的。

我们可以循环该对象并拥有一个单独的数组,仅保存键值,然后通过该键值编号获取值。

我真的不确定这里有什么好的解决方案,我只是抛出我的想法、想法?

最佳答案

JavaScript 对象不是哈希表,在现代引擎上,只有删除其中的属性时,哈希表才会在其实现中使用。否则,它们是高度优化的运行时生成的类的实例。这些对于当前的问题来说都不重要。 :-)

假设您希望在 0 属性和指定属性之一之间建立持续的链接,则在 ES5 及更早版本中无法做到这一点。相反,您需要 getter/setter 方法来进行索引访问:

Object.defineProperty(foo, "item", {
    value: function(index, value) {
        var key = Object.keys(this).sort(orderingFunction)[index];
        if (arguments.length < 2) {
            // Getter
            return this[key];
        }
        // Setter
        this[key] = value;
        return this;
    }
});

...其中 orderingFunction 是定义键顺序概念的函数。 (在 ES5 及以下版本中,属性没有顺序。而在 ES2015 及以上版本中,属性确实有顺序,但 A)无用,B)不保证是 Object.keys 返回的顺序。 )

用法:

foo.item(0); // "value"
foo.item(0, "new value");

或者,如果您愿意,可以对 getter 和 setter 使用单独的函数。

请注意,由于所有这些排序,这是相当昂贵的。

<小时/>

在 ES2015 及更高版本中有一种方法可以做到这一点:a Proxy对象,它可以在这里做两个关键的事情:

  1. 实现可用于数字访问的默认属性访问函数

  2. 允许您维护键数组,而不必不断地重新排序

// REQUIRES ES2015+ SUPPORT IN YOUR BROWSER
let foo = {
  question: "Life, the Universe, and Everything!",
  answer: 42
};
let rexNumber = /^\d+$/;
let fooProxy = indexedProxy(foo);
console.log(fooProxy[0]); // 42
fooProxy.answer = 67;
console.log(fooProxy[0]); // 67
fooProxy.bar = "foo";
console.log(fooProxy[1]); // "foo"

function indexedProxy(obj) {
  // An array of the current keys
  let keys = getKeys(foo);

  // Return the proxy
  return new Proxy(obj, {
    // Called when any property is gotten from the target
    get(target, property) {
      if (rexNumber.test(property)) {
        // Indexed access
        let key = keys[property];
        return key === undefined ? undefined : target[key];
      }
      // Normal access
      return target[property];
    },
    // Called when any property is set on the target
    set(target, property, value) {
      if (rexNumber.test(property)) {
        // Indexed access
        let key = keys[property];
        if (key === undefined) {
          throw new Error(`No property for index #{property}`);
        }
        target[key] = value;
      } else {
        // Normal access, do we know the key?
        let newProp = !keys.includes(property);
        target[property] = value;
        if (newProp) {
          // Rebuild our array
          keys = getKeys(target);
        }
      }
    }
  });
}

function getKeys(obj) {
  // Let's go for alphabetical
  return Object.keys(obj).sort((a, b) => a.localeCompare(b));
}

代理也不便宜,但希望其性能比您不断生成和排序的数组更好。

显然上面只是一个示例,而不是高度优化的通用工具。它没有使用数组索引的正确定义(详细信息隐藏在 this answer 中),它使用更简单的“都是数字吗?”定义。它只处理对象自己可枚举属性;如果你想处理继承的属性或标记为不可枚举的属性,这是可能的,只需要调整上面的thea。

关于javascript - 将索引号分配给 JavaScript 对象键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39038243/

相关文章:

javascript - JS - 强制函数在其他函数之后运行

javascript - 在另一个函数的参数中捕获函数中的错误

javascript - jquery从数组中删除元素

javascript - HTML 选择器上的 .val() 没有输出

javascript - 使用javascript scrollTop函数时选择框关闭

javascript - 过渡不适用于高度

javascript - 使用js函数的原型(prototype): How to know the prototype. js版本?

javascript - 在odoo中隐藏和显示textarea

javascript - 将 slider 的下一张和上一张按钮更改为下一张或上一张图片的预览

javascript - 从选项卡切换到折叠以响应