【问题标题】:Can I make a "Virtual Array" in JavaScript?我可以在 JavaScript 中创建“虚拟数组”吗?
【发布时间】:2014-08-15 07:11:15
【问题描述】:

我正在调用一个 JavaScript 函数,该函数希望显示一系列内容。它显示一个计数,并一个一个地显示项目。当我传递一个普通的 JavaScript 数组时,一切正常。

但是我有太多的东西要一次记住。我想要做的是,将一个与数组具有相同接口的对象传递给它,并在函数尝试访问数据时调用我的方法。事实上,如果我通过以下:

var featureArray = {length: count, 0: func(0)};

然后显示计数,并正确显示第一项。但我不想分配所有条目,否则我会耗尽内存。当用户尝试显示第二个项目时,该功能当前崩溃。我想知道何时访问第 1 项,并为第 1 项返回 func(1),为第 2 项返回 func(2),等等(即,延迟创建该项目,直到它被请求)。

这在 JavaScript 中可行吗?

【问题讨论】:

  • 那么,当用户调用 featArray[0] 你希望它执行 func(0) 并给你值?为什么用户不能只使用 func(0) 代替?
  • 如果你有太多的项目要保存在内存中,你认为你有足够的内存来显示所有这些吗?
  • 你从哪里得到所有这些物品?
  • @Bergi - 也许他正在过滤它们,只显示符合特定标准的一些。
  • 好吧,这将有助于查看您的代码片段。这些物品是从哪里来的?它们是如何生成的?

标签: javascript arrays virtual


【解决方案1】:

如果我理解正确,这将有所帮助:

var object = {length: count, data: function (whatever) {
    // create your item
}};

那么,您可以使用object.data(1)object.data(2) 等等,而不是array[1]array[2] 等等。

【讨论】:

  • 如果我可以更改代码,那就行了。但是被调用的函数不是我的,它需要一个数组。
【解决方案2】:

由于似乎存在一个约束,即必须通过普通数组索引arr[index] 使用数组索引访问数据并且无法更改,因此答案是不,您不能在 Javascript 中覆盖数组索引改变它的工作方式并制作某种只根据需要获取数据的虚拟数组。它是为 ECMAScript 4 提出的,但作为一个特性被拒绝了。

有关其他讨论/确认,请参阅这两个其他帖子:

How would you overload the [] operator in Javascript

In javascript, can I override the brackets to access characters in a string?

解决这个问题的通常方法是改用.get(n)之类的方法来请求数据,然后.get()的实现者可以随心所欲地虚拟化。


附:其他人表示您可以在 Firefox 中为此使用 Proxy 对象(据我所知,其他浏览器不支持),但我个人并不熟悉 Proxy 对象,因为它的使用似乎仅限于仅针对 Firefox 的代码现在。

【讨论】:

  • 只要受支持,您可以使用Proxy 进行操作。
  • @plalx - 随时解释。
  • @plalx - 您能否展示或参考使用代理(目前似乎仅在 Firefox 中支持)来重载数组索引的示例?
  • 当然,像var arrProxy = new Proxy({}, { get: function (target, name) { if (/*name is a number*/) return /*some computation*/; } }); 这样的东西基本上是一个代理让你拦截目标对象上的每个属性访问。显然,您还必须实现数组接口的其余部分。
【解决方案3】:

是的,可以随时随地生成项目。你会想看看Lazy.js,一个用于生成延迟计算/加载序列的库。

但是,您需要更改接受此序列的函数,它的使用方式与普通数组不同。


如果你真的需要伪造一个数组接口,你会使用Proxies。可惜只是和声草稿,目前只有supported in Firefox' Javascript 1.8.5

假设数组只在一次迭代中被访问,即从索引0开始,你也许可以用getter做一些疯狂的事情:

var featureArray = (function(func) {
    var arr = {length: 0};
    function makeGetter(i) {
        arr.length = i+1;
        Object.defineProperty(arr, i, {
            get: function() {
                var val = func(i);
                Object.defineProperty(arr, i, {value:val});
                makeGetter(i+1);
                return val;
            },
            configurable: true,
            enumerable: true
        });
    }
    makeGetter(0);
    return arr;
}(func));

但是,我建议避免这种情况,而是切换期望数组的库。如果对“数组”进行任何其他操作但按顺序访问其索引,则此解决方案非常容易出错。

【讨论】:

  • 约束似乎是必须通过数组索引来获取数据。
  • @Bergi Hum,非常聪明。没有考虑过按需生成吸气剂。然而,OP的问题似乎没有多大意义。除非他的项目来自生成器函数(可能是无限的),否则如果没有足够的内存,我不明白他计划如何独立于使用的方法返回它们。如果它们来自网络服务,他可能只是将处理分成多个批次。
  • 是的,我不明白 OPs 代码的确切安排和他的问题。看起来他有一个他无法更改的处理功能,因此它可以处理大量数据。
【解决方案4】:

感谢所有评论并回答了我最初的问题的人 - JavaScript 似乎(目前)不支持。

我能够绕过这个限制,并且仍然可以做我想做的事。它使用了我在原始问题中没有提到的程序的一个方面(我试图简化问题),因此其他人不能推荐这个是可以理解的。也就是说,从技术上讲,它并不能回答我最初的问题,但我会分享它以防其他人觉得它有用。

事实证明,每个数组元素中的对象的一个​​成员是一个回调函数。也就是说(使用我最初问题中的术语), func(n) 正在返回一个对象,该对象在一个成员中包含一个函数,该函数由传递数据的方法调用。由于这个回调函数知道它所关联的索引(至少,当由 func(n) 创建时),所以它可以在调用时添加数组中的下一项(或至少确保它已经存在)。一个更复杂的解决方案可能会提前,和/或落后,和/或可以清理不靠近当前索引的项目以释放​​内存。这一切都假设这些项目将被连续访问(在我的程序中就是这种情况)。

例如,

1) 创建一个将保留在范围内的变量(例如,一个全局变量)。

2) 使用我在原始问题中作为示例给出的对象调用函数:

var featureArray = {length: count, 0: func(0)};

3) func() 可以是这样的:

function func(r) {
    return {
        f : function() {featureArray[r + 1] = func(r + 1); DoOtherStuff(r); }
    }
}

假设 f() 是函数的成员,该函数将被外部函数调用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多