Javascript 作为数组进行迭代,但仍可通过键访问

Javascript 作为数组进行迭代,但仍可通过键访问,javascript,arrays,object,key-value,for-in-loop,Javascript,Arrays,Object,Key Value,For In Loop,我正在为简单的2D游戏编写自己的游戏引擎,并希望迭代子项,但出于某种原因,我希望通过一个键访问每个项 也许有人知道我下面的问题有什么好的解决方法吗? 问题1 我不能在中使用Object.keys和for,因为简单数组迭代的性能提高了5倍。性能至关重要 问题2 我想通过将子对象传递给函数来轻松添加/删除子对象: 场景。添加(儿童); 场景。移除(儿童); 解决方案#1? 我可以创建包含子数组和对象的数据结构。使用添加/删除方法同时填充数组和对象。当然,在更改children属性的情况下,您将破

我正在为简单的2D游戏编写自己的游戏引擎,并希望迭代子项,但出于某种原因,我希望通过一个键访问每个项

也许有人知道我下面的问题有什么好的解决方法吗?

问题1 我不能在中使用
Object.keys和for,因为简单数组迭代的性能提高了5倍。性能至关重要

问题2 我想通过将子对象传递给函数来轻松添加/删除子对象:

场景。添加(儿童);
场景。移除(儿童);

解决方案#1? 我可以创建包含子数组对象的数据结构。使用添加/删除方法同时填充数组和对象。当然,在更改
children
属性的情况下,您将破坏这些内容,但这不是我的情况,您必须使用add/remove

实例 渲染。每个着色器程序都有子数组

_render(...args) {
    const [gl, scene, camera] = args;
    const { childrenByShaderProgram } = scene;
    const dt = 0;

    gl.clearColor(0, 0, 0, 1);
    gl.clear(gl.COLOR_BUFFER_BIT);

    camera.updateViewMatrix();

    scene.beforeUpdate(dt);

    Object.keys(childrenByShaderProgram).forEach(uuid => {
      const children = childrenByShaderProgram[uuid];
      const sp = children[0].shaderProgram;

      // Per shader program rendering.
      this._useShaderProgram(gl, sp);

      // Update view matrix uniform value.
      sp.updateUniform('u_v', camera.viewMatrix);

      for (let j = 0, len = children.length; j < len; j += 1) {
        const child = children[j];

        // Update attributes and uniforms values.
        scene.updateEachChild(child, dt);

        // Apply changes by binding uniforms and attributes.
        sp.bindUniforms(gl);
        sp.bindAttributes(gl);

        // tbd @andytyurin texture implementation should be here.
        gl.drawArrays(gl.TRIANGLE_STRIP, 0, Math.floor(child.vertices.length / 2));
      }
    });

    scene.afterUpdate(dt);

    window.requestAnimationFrame(() => this._render(...args));
  }
在这个示例中,我使用
renderingIdx
从数组中更快地删除子对象,但我不想在每个子对象中保留任何属性。因此,作为替代方案,我可以将子项保存在两种变体中,即键值数组。它将在渲染时提供相同的性能,并在场景中添加和删除子对象时提供相同的性能


谢谢大家!

你提出的解决方案就是要走的路。为了跟踪键,最好编写一个包装器类:

class LookupArray {
 constructor(key, ...entries) {
  this.key = key;
  this.array = [];
  this.hash = {};
  this.push(...entries);
  }
  push(...entries) {
   for(const entry of entries) {
     this.hash[entry[this.key]] = entry;
     this.array.push(entry);
    }
   return entry.length;
  }
  get(id) {
  return this.hash[id] || this.array[id];
  }
}
因此,我们可以:

const lookup = new LookupArray("length", "abcd", "defghi");
console.log(
  lookup.get(0), // "abcd"
  lookup.get(4), // "abcd"
);

for(const entry of lookup.array)
  console.log(entry);


但是我想你可以通过
Object.entries
来获得类似的性能,而且内存更少。如评论中所述。

我只是想建议维护一个单独的对象键数组,但看起来这是你的第一个计划,我想试试,看看它在性能方面与for..in.相比如何。@PatrickRoberts
forEach
比simple
for
慢。我不能使用
array.entries()
,我需要使用键,而不是索引。但是使用
object.entries()
的想法看起来很有趣,但仍然需要比较性能。@不幸的是,AndyTyurin
object.prototype.entries()
实际上已从规范中删除。您可以实现polyfill,但它的性能不会像您预期的那样好。所有可用的是静态的
对象.entries()
,它创建了一个键/值对数组,并且不是懒惰的。@PatrickRoberts嗯,看起来它离使用
对象.keys进行迭代不远了。顺便说一句,我将尝试在主题中放置一些代码。@Ninjaner抱歉,我错过了为什么我们需要将数组转换为对象?顺便说一下,使用非严格类型的回退(
hash[id]
其中
id
应该是字符串,
array[id]
其中
id
应该是索引),可能会阻止函数的可能优化。也许它应该被分成两个函数,一个是
getKey()
,另一个是
getIndex()
,因为调用代码无论如何都不应该混合这两种情况。好主意,但是它是如何工作的呢
this.hash[entry[this.key]]=entry条目应该是
String
,因为我们正在使用
来表示字符串的类型和数组。看起来它与解决方案非常相似#1@PatrickRoberts这更像是一个概念证明而不是最终版本,是的,我得到了通知。。。thanks@AndyTyurin对于对象来说,这可能最有意义,但对于字符串,它的输入更少:)
const lookup = new LookupArray("length", "abcd", "defghi");
console.log(
  lookup.get(0), // "abcd"
  lookup.get(4), // "abcd"
);

for(const entry of lookup.array)
  console.log(entry);