Javascript 作为数组进行迭代,但仍可通过键访问
我正在为简单的2D游戏编写自己的游戏引擎,并希望迭代子项,但出于某种原因,我希望通过一个键访问每个项 也许有人知道我下面的问题有什么好的解决方法吗? 问题1 我不能在中使用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属性的情况下,您将破
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.相比如何。@PatrickRobertsforEach
比simplefor
慢。我不能使用array.entries()
,我需要使用键,而不是索引。但是使用object.entries()
的想法看起来很有趣,但仍然需要比较性能。@不幸的是,AndyTyurinobject.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);