通过查找 table 函数名称来调用 javascript 函数(或方法)的最快方法?

Fastest way to call a javascript function (or method) via a lookup table of function names?

我正在用 JavaScript 模拟一个 8 位微处理器。我将每个操作码函数名存储在一个数组中,并根据从我的虚拟内存中读取的操作码调用这256个函数中的每一个,如下所示:

this.OP[opcode] = 'this.LDAA()';
eval(this.OP[opcode]);

我最近更改了我的代码以删除 eval(),如下所示:

this.OP[opcode] = 'LDAA';
this[this.OP[opcode]]();

在 Mac Safari 中,上述两者之间没有明显的速度差异,这让我感到惊讶。我认为后者会更快,但两者的虚拟时钟速度大致相同(目前峰值为 4MHz)。

与使用 eval() 相比,使用索引方法调用似乎没有速度损失,因此我也希望更新我的虚拟内存系统,但我对要使用的语法有心理障碍。

写一个字节我有:

RAM = {
    write : [],
    setup : function() {
        this.write[addr] = "this.simpleWrite(addr,byte)";
    },

    writeByte : function(addr,byte) { 
        eval(this.write[addr]);
    },

    simpleWrite : function(addr,byte) { 
        this.memory[addr] = byte;
    },
};

RAM.writeByte( someAddress, someValue );

我正在使用这种索引的间接方法,因此我可以将设备映射到地址范围并根据需要放置断点和观察点,所有拦截内存读取和写入 - 最大限度地提高性能。

关于如何在保持数据吞吐量的同时丢失 eval 的任何建议?

我想将外部方法映射到间接数组中,并能够传递参数(要写入的值)。因此,无论哪个虚拟硬件使用公共接口访问虚拟内存,其他虚拟硬件都可以拦截进程并在必要时监控或更改值。

你试过了吗:

setup : function() {
    this.write[addr] = "simpleWrite";
},

writeByte : function(addr,byte) { 
    this[this.write[addr]](addr,byte);
},

或者看看这个: whosebug.com/questions/1986896/what-is-the-difference-between-call-and-apply

theFunction.apply(valueForThis, arrayOfArgs)

theFunction.call(valueForThis, arg1, arg2, ...)

将我的评论变成答案,因为这听起来像你要做的:

如果您恰好有 256 个操作码,那么使用操作码索引数组以获取函数的 256 个函数引用(不是函数名称)的数组应该是最快的。如果你在操作码中有任何漏洞(例如,没有使用所有 256 个操作码),你只需为你没有使用的那些填充一个虚拟函数引用。如果你有任何共同的功能(服务于多个操作码的功能),只需多次使用相同的功能引用。这个想法是您想要一个 256 元素的数组,您可以使用操作码直接对其进行索引以获取要执行的函数。

在某些 JS 引擎中,解释器可以很好地优化仅被视为纯数组的数组,这比对象键查找要好得多。

与所有与性能相关的问题一样,您必须在相关浏览器中进行测试才能确定。使用 eval() 不太可能是最快的,因为它必须首先从头开始解析代码然后执行它。

使用问题中详述的 eval 方法的替代方法:

RAM = {
    memory : [],
    write : [],
    setup : function() {
        for (var addr = start; addr < length; ++addr) {
            this.write[addr] = 
                function(a) { 
                    function(byte) { 
                        RAM.memory[a] = byte 
                    }
                }(addr);
            }
        }
    }
RAM.setup();
RAM.write[validAddress](byteValue);

这比使用初始评估方法(在 Mac Safari 中)快大约 5%。它也更整洁并且删除了 eval 的使用。 for...循环中函数定义的复杂性是由于在设置函数本地创建的变量 addr 的范围。如果直接使用,则指向此变量的指针将传递给内部函数,并且当循环完成时,所有数组元素将具有相同的 'address' 作为循环结束时 addr 的值(开始+长度)。因此,我通过外部函数在循环的每次迭代中创建一个新的局部变量 (a),它是一个常量,并且在每个内部函数中(通过指针)使用该值。

另请注意,我使用对象名称 (RAM) 而不是 .this 访问内存数组,因为其他对象可能会间接访问内部方法并导致 .this 引用调用对象。直接命名对象就解决了这个问题。

有关在循环内创建函数的更详细示例和说明,请参阅 callbacks in loops