Javascript 引擎会进行这种优化吗?

Do Javascript engines do this kind of optimisation?

注意我已经阅读了一些有关 JS 引擎优化的文章,但其中大部分内容太过技术化,我无法充分理解以应用于此问题。我也知道并非所有引擎都是相同的。我想我会对 V8 和 Rhino 的处理特别感兴趣。

如果我创建一个 table,然后是行,然后是单元格...然后我想在所有这些单元格上放置相同的键事件侦听器。

不仅为每个单元格创建这些侦听器需要一定的时间,这对于较大的 table 来说可能很重要,而且我还假设每个侦听器函数都存储在它自己的,即使每个侦听器函数实际上是相同的。

我可以使用的另一种关键事件侦听器方法是在 TABLE 上放置一个关键事件侦听器,并在 运行 期间对每个 keydown 事件进行计算, 哪个单元触发了这个事件。我可以通过

let elementOfInterest = document.activeElement;

"Get the currently focused element in the document" 来自 here.

根据我的实验,如果您在 table 单元格中键入,这个 TD 确实有焦点并且确实由上述调用返回。

这样,我只需要创建一个侦听器,我认为这会更快并且占用更少的内存。唯一(非常)轻微的缺点是必须花费时间通过上述调用获得此 "active element" 。而且,很可能,某些东西会以意想不到的方式抓住焦点的风险 - 显然,如果你想监听单元格中文本的变化,最不容易出错的技术必须是使用附加到该单元格的监听器。

但我只是想知道:也许 Java 脚本比这更聪明:也许如果您创建 100 个单独的单元侦听器,某处将它们标识为 "all the same" 并且只在内存中创建一个函数。例如,这是您通常期望从 Java 编译器获得的优化类型。

有过这样的优化吗? Javascript 处理这样的案例有多聪明?还是只是"script and that's it":所见即所得?

语言本身的语义不允许将两个函数表达式 "merged" 合二为一,即使它们在功能上是等价的:

> a = function(){return 'foo'};
ƒ (){return 'foo'}
> b = function(){return 'foo'};
ƒ (){return 'foo'}
> a === b
false

此外,当您开始考虑函数的闭包(例如它使用的外部名称)时,事情会变得更加棘手。

所以不,开箱即用。

但是,对于您的用例,有两个优化:

  • 正如您所发现的,您可以使用 事件冒泡 并在祖先元素上添加事件侦听器并使用 event.target (最好而不是 document.activeElement) 找出它最初的目标位置(event.currentTarget 将是处理程序所在的节点)
  • 如果你不能使用共同的祖先(提示:你几乎总是可以;document 是一个有效的目标),你可以定义一次函数(假设它不需要关闭任何动态变化的变量)并再次使用 event.target,例如event.target.dataset 找出您正在处理的数据。

下面是展示两者的片段。

function createButton(parent, datum) {
  const btn = document.createElement("button");
  btn.dataset.datum = datum;
  btn.innerHTML = datum;
  parent.appendChild(btn);
  return btn;
}

function eventHandler(event) {
  if(event.target.tagName !== "BUTTON") return;
  const msg = `real target: ${event.target} (datum="${event.target.dataset.datum}")\ncurrent target: ${event.currentTarget}`;
  alert(msg);
}

const p2 = document.getElementById("parent2");

// bubbling listener
const p1 = document.getElementById("parent1");
p1.addEventListener("click", eventHandler, false);
for(var i = 0; i < 10; i++) {
  createButton(p1, "p1-" + i);
}


// same function on multiple elements
for(var i = 0; i < 10; i++) {
  createButton(p2, "p2-" + i).addEventListener("click", eventHandler, false);
}
<div id="parent1"></div>
<div id="parent2"></div>