数组与 If 性能在索引循环中



哪一个性能更好?如果语句更具可读性,但是如果我在数组(数据库式)中生成值并使我的 for 循环基于当前索引调用函数,以便更容易进一步编辑,该怎么办?

var msg = [
"You are now viewing Tab number one",
"You are now viewing Tab number two",
"You are now viewing Tab number three",
"You are now viewing Tab number four"
]
var button = document.getElementsByTagName("button")
for (var i = 0, len = button.length; i < len; ++i) {
(function(index) {
button[i].addEventListener("click",
function() {
document.getElementById("msg").innerHTML = msg[index];
});
})(i);
}
<button>Tab1</button>
<button>Tab2</button>
<button>Tab3</button>
<button>Tab4</button>
<br>
<p id="msg">Message here</p>

var button = document.getElementsByTagName("button")
for (var i = 0, len = button.length; i < len; ++i) {
(function(index) {
button[i].addEventListener("click",
function() {
if (index==0){
document.getElementById("msg").innerHTML = "You are now viewing Tab number one";
}
if (index==1) {
document.getElementById("msg").innerHTML = "You are now viewing Tab number two";
}
if (index==2) {
document.getElementById("msg").innerHTML = "You are now viewing Tab number three";
}
if (index==3) {
document.getElementById("msg").innerHTML = "You are now viewing Tab number four";
}
});
})(i);
}
<button>Tab1</button>
<button>Tab2</button>
<button>Tab3</button>
<button>Tab4</button>
<br>
<p id="msg">Message here</p>

这就像问我应该为我的简单数字时钟使用哪种高端显卡? 性能差异可以忽略不计。使用 iife 而不是let已经比您的实际问题、数组索引与多个 ifs 对性能的影响更大。

这仍然无关紧要。

关于选项,我发现它们都很难阅读,尤其是随着按钮数量越来越大。

怎么样?

document.querySelector(".buttons").addEventListener("click", function(event) {
const button = event.target.closest("button[data-msg]");
if (button) {
document.querySelector("#msg").innerText = button.dataset.msg;
}
})
<div class="buttons">
<button type="button" data-msg="You are now viewing Tab number one">Tab1</button>
<button type="button" data-msg="You are now viewing Tab number two">Tab2</button>
<button type="button" data-msg="You are now viewing Tab number three">Tab3</button>
<button type="button" data-msg="You are now viewing Tab number four">Tab4</button>
</div>
<p id="msg">Message here</p>

海事组织。 很好,而且是声明性的。并且易于扩展。

条件if(button)处理除了这些按钮之外,您可能向div.buttons添加其他可以单击的内容的可能性。

.closest("button[data-msg]")delas 包含您可以在可能触发事件的按钮中添加更多标记的情况。我们想要<button data-msg="...">

对于 4 个项目,甚至 40 个项目,性能无关紧要:计算机非常快,列表很短。更重要的是阅读和维护的难度。

性能

但值得研究一些潜在的性能原则,特别是在列表方面,因为小列表有一种令人讨厌的变大趋势。

button[i]这样的数组查找是常量时间或 O(1)。这意味着无论button获得多大,查找都将始终花费相同的时间。

而一连串的if语句或switch必须尝试每一个,直到找到匹配的语句。最好的情况是i始终为 0,并且必须比较 1 次。最坏的情况是i总是 3 次,它必须比较 4 次。如果i均匀分布,那么平均需要 2 次。这称为线性时间或 O(n),查找的时间随着button大小的增加而增加。如果button变得两倍,时间就会变长两倍。

随着数组变大,阵列查找button性能将保持不变。随着 if 语句变大,button性能会变差。

可读性

现在,开始时,您会发现线性代码更容易阅读。您希望将所有内容按照执行顺序显示在页面上。但是随着代码变得越来越复杂,这很快就会变得势不可挡,并将导致大量违反 DRY 原则的剪切和粘贴代码:不要重复自己。

有经验的程序员发现,最好把尽可能多的细节推到其他地方,这样人们就可以清楚地看到重要的部分。重要的部分是它为每个按钮生成单击处理程序,该按钮添加了来自msg的消息。不重要的正是这个信息是什么。

您可以通过从循环中提取函数来使代码更简单,并可能节省一些内存。

var addMsgListener = function(element, message) {
element.addEventListener("click",
function() {
document.getElementById("msg").innerHTML = message;
}
)
};
var buttonMessages = [
"You are now viewing Tab number one",
"You are now viewing Tab number two",
"You are now viewing Tab number three",
"You are now viewing Tab number four"
]
var button = document.getElementsByTagName("button")
for (var i = 0, len = button.length; i < len; ++i) {
addMsgListener(button[i], buttonMessages[i]);
}

请原谅我可能很糟糕的Javascript。

现在很清楚这个循环的作用,对于每个按钮,它都会添加一个消息侦听器。如果我关心消息侦听器是什么,我可以选择查看addMessageListener。或者我可以跳过它。这使得代码"可略读";人们可以阅读代码以了解它的作用,并且仅在必要时深入研究细节。这不是线性阅读,但这是您会习惯并喜欢的东西。

请注意,addMsgListener不再指msg,也不再指button。这些是由使用它的循环选择的。它现在是通用的,可用于其他元素和消息。

现在,更多的可重用性将显现出来;事件和ID是否需要硬编码?这种在不更改代码功能的情况下更改代码的过程称为重构。

保养

每次你想要改变一条消息时,你都必须改变代码。如果要添加消息,则必须添加代码并重新编号。如果要删除消息,则必须删除代码并重新编号。如果要对邮件重新排序,则必须重新编号。这需要开发人员了解什么是 UI 更改。而且这个过程容易出错,如果你删除一条消息而忘记更改索引怎么办?

通过将消息放入数组中,您只需更改msg.如果要添加消息,请在msg中添加一行。如果要删除邮件,请从msg中删除一行。如果要对邮件重新排序,请重新排序msg

msg不必存在于代码中,它可以进入配置文件,使非编码人员更容易更改。

远距离行动

这就引出了最后一个问题:msg需要与按钮的长度和顺序相同。每次更改 HTML 时,都可能需要更改msg,反之亦然。但是按钮及其消息位于不同的位置。这被称为远距离操作:更改代码的一部分会受到代码中完全不同的部分的影响。

为了避免这种情况,您可以为每个按钮提供一个classid,并据此索引其消息。这至少意味着按钮和消息不依赖于它们的确切顺序。如果您不确定 HTML 中将存在哪些按钮,但希望为所有可能的按钮提供消息,这将非常有用。

var msg = {
car: "🏎",
truck: "🚚",
train: "🚆",
plane: "✈"
}

你可以走另一条路;在Javascript中生成按钮及其消息。它仍然将有关每个按钮的所有信息保存在一起。如果按钮是动态的并且可以更改,这将非常有用。

您可以按照托马斯的建议进行操作,并将消息附加到按钮本身。然后,有关按钮的所有数据都在一起。如果添加、删除或重新排序按钮,消息仍然有效。这允许人们只处理 HTML。

在这种情况下,使用tabindexdata-index属性可能是个好主意。示例代码段不涉及循环,而是使用data-index

var msg = [
"You are now viewing Tab number one",
"You are now viewing Tab number two",
"You are now viewing Tab number three",
"You are now viewing Tab number four"
]
document.body.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
if (e.target.tagName == 'BUTTON') {
document.getElementById('msg').innerHTML = msg[e.target.dataset['index']];
}
});
<button data-index="0">Tab1</button>
<button data-index="1">Tab2</button>
<button data-index="2">Tab3</button>
<button data-index="3">Tab4</button>
<br>
<p id="msg">Message here</p>

编辑

如果要有大量选项卡,请尽量避免使用tabindex。以下部分摘自 MDN

避免使用大于 0 的 tabindex 值。这样做就可以 依赖辅助技术的人难以导航和 操作页面内容。相反,使用元素编写文档 逻辑序列。

此外,tabindex的最大值为 32767。

最新更新