欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JavaScript重构技术:特定于通用代码

程序员文章站 2022-06-01 21:02:08
...

这篇文章是由同行评审太子丹 感谢所有SitePoint的审稿作出SitePoint内容也可以是最好的!

最近的线程上SitePoint的论坛上,得到了一些代码,让一个下拉框控件时,另一个下拉框是可见的。 即使代码工作得很好,我意识到,这留下许多不足之处。 这是脆,不能承受哪怕是很小的变化伴随的HTML。

原来这里是CSS代码:

 #second { display: none; }
#second.show { display: block; }
 

和原来的JavaScript代码:

 document.getElementById("location").onchange = function () {
  if (this[this.selectedIndex].value === "loc5") {
    document.getElementById("second").className = "show";
  } else {
    document.getElementById("second").className = "";
  }
};
 

在这篇文章中,我将证明,可以应用到上面的代码,以使其更容易重用,更适应未来变化的一些简单的JavaScript重构技术。

知道哪些路该如何走

JavaScript有很多方法可以实现相同的任务,其中有些工作比别人做得更好。 有没有什么方法,现在这样我们就不必在以后回来给它来提高代码? 当然! 但是,当有做一些事情的几种可能的方法,我们如何才能确定哪一个是可能效果最好?

为了提高代码的一种常见方法是删除重复(使用不重复自己的原则)。 从那里,虽然,它可以从具体转到更通用的代码,使我们能够处理更广泛的情况下更加有用。

具体的代码往往是易碎的,当涉及到处理未来的变化。 代码不存在于真空中,并且将需要应对它周围,在HTML代码中的其他行动来改变。 凭借以往的经验,虽然利益,我们可以看看发生并且减少次数,我们需要重新审视代码改进常见的变化。 不变的是,你会发现,这意味着使代码更通用。

但要小心! 它可以很容易使我们的代码太一般化,它变得很难理解的地步。 引人注目的通用性和可读性之间的良好平衡是我们找到改进的代码。

JavaScript的重构技术:具体到通用

在期间测试驱动开发 (TDD),你不能不过这个原则来作为过程的一部分:

由于测试得到更具体的,代码变得更通用。

TDD的周期由罗伯特C.马丁涵盖这个想法很好。 这里的主要好处是,通用的代码最终能够处理更广泛的情况和场景。

请注意,如果您想了解更多关于TDD,看看我们的短迷你课程测试驱动开发Node.js的

看着上面的代码中,一些明显的具体的仿制改进是立即可用。

  • 存储变量的字符串将有助于我们从一个地方进行维护。
  • onchange事件处理程序是迄今有问题的,因为它可以被覆盖。 我们应该考虑使用addEventListener代替。
  • className属性将覆盖现有的类名。 我们应该考虑使用classList来代替。

使所有的这些改进之后,我们将用代码,更好地适应未来的变化,并且更易于更新结束。 因此,让我们开始吧...

使用变量来防止重复建设

下拉框(“位置”)和它的触发值(“loc5”)的ID是有用的参考,以保持在一起。 第二<select>元件也被称为两次,这是我们可以拉出到一个单独的变量,以防止杂波和提供更容易maintenence

例如,而不是两个引用将需要如果该元素的ID改为更改相同的元素:

 // bad code
if (...) {
  document.getElementById("second").className = "show";
} else {
  document.getElementById("second").className = "";
}
 

我们可以存储在一个变量这个元素的引用,限制只有在变量指定的地方未来的变化:

 // good code
var target = document.getElementById("second");
if (...) {
  target.className = "show";
} else {
  target.className = "";
}
 

通过拉动这些字符串一起出去到代码的顶部,并分离出如果条件的部分,具体到一般的技术导致代码更容易维护,无论是现在还是将来。 如果任何标识或选项值的改变,他们都可以很容易地在一个地方发现的,而不是通过他们的所有OCCURENCES的代码打猎。

 // improved code
var source = document.getElementById("location");
var target = document.getElementById("second");
var triggerValue = "loc5";

source.onchange = function () {
  var selectedValue = this[this.selectedIndex].value;
  if (selectedValue === triggerValue) {
    target.className = "show";
  } else {
    target.className = "";
  }
};
 

提高事件处理

传统的事件处理程序仍然相当流行(并已在此情况下正确使用),但他们有一些问题。 其中最主要的是,在这样设定的事件处理程序的元素时,您将覆盖同一事件的任何先前的处理程序。

 // bad code
source.onchange = function () {
  // ...
};
 

目前上面的代码工作。 我们可以使用测试证明这一点。


有关测试快速笔记

经营理念 :测试,以确保你的代码写在你所期望的方式行事的一个好方法。 他们减少,改变你对代码的事业别的东西在其他地方的代码打破的可能性。 测试的介绍是不幸之外本文的范围(虽然SitePoint有很多精彩的内容在这个题目)。 你仍然可以在没有你的生活写过一个测试跟随一起。

语法 :下面的测试使用茉莉花测试框架。 茉莉花测试(又名规格)通过调用全球茉莉花定义it功能,这需要一个字符串和进一步的功能作为参数。 该字符串是规范的名称和功能是规范本身。 你可以阅读更多关于茉莉对项目的主页

请注意,本文将着重测试前端代码。 如果你正在寻找的东西集中在后端,一定要看看我们的课程: 测试驱动开发的Node.js


运行测试

鉴于我们的代码之前的状态,下面的两个测试将通过:

 it("should add the 'show' class name when the 'loc5' option is selected", function() {
  changeSelectTo(source, "loc5");
  expect(target.classList.contains("show")).toBe(true);
});

it("should remove the 'show' class name when an option value different from 'loc5' is selected", function() {
  changeSelectTo(source, "loc2");
  expect(target.classList.contains("show")).toBe(false);
});
 

changeSelectTo功能改变的值<select>元素和期望(使用茉莉花内置expect查明该元素具有正确的类名功能)。

但只要onchange的处理程序被改变-这是一件好事任何其他代码能够做到的事情-更改的类名丢失,事情开始出错的功能。 我们可以进一步的测试证明这一点:

 it("should toggle the class name even when the onchange event is replaced", function () {
  changeSelectTo(source, "loc2");
  expect(target.classList.contains("show")).toBe(false);

  // Overwrite the onchange handler
  source.onchange = function doNothing() { return; };

  changeSelectTo(source, "loc5");
  expect(target.classList.contains("show")).toBe(true); // fails
});
 

这个测试失败,因为中可以看到这个CodePen 请注意,茉莉花特定代码是在一个单独的笔,发现这里

重构我们的代码以使测试通过

我们可以很容易地通过使这个测试通过的addEventListener ,这使得被分配给一个事件的任何数量的功能。 false参数状态事件捕获(当是否true )或事件冒泡时( false )用于事件的顺序。 怪异模式给出了很好的概述事件顺序的事件。

 // good code
source.addEventListener("change", function (evt) {
  // ...
}, false);
 

这里的代码是如何受此更改的影响:

 // improved code
var source = document.getElementById("location");
var target = document.getElementById("second");
var triggerValue = "loc5";

source.addEventListener("change", function () {
  var selectedValue = this[this.selectedIndex].value;
  if (selectedValue === triggerValue) {
    target.className = "show";
  } else {
    target.className = "";
  }
}, false);
 

随着addEventListener的测试线的所有活动现在都通过了。

见笔mAbzLL由SitePoint( @SitePoint上) CodePen

:在测试代码,我命名的功能toggleShowOnSelectedValue ,测试不同的时,更容易使你的方法之间交换onchange技术:

 //source.onchange = toggleShowOnSelectedValue;
source.addEventListener("change", toggleShowOnSelectedValue, false);
 

给它在上面的CodePen一试。 试试切换注释掉线,看看会发生什么。

改善类处理

与代码的另一个问题是,第二个<select>元素将失去以往任何类,它可能有,由于className更换任何在那里了。

 // bad code
target.className = "show";
 

我们可以看到在这个问题发生下列故障,这需要一个类的indent仍然是选择的元素上显示后:

 it("should retain any existing class names that were on the target element", function () {
  changeSelectTo(source, "loc2");
  target.classList.add("indent");
  expect(target.classList.contains("indent")).toBe(true);

  changeSelectTo(source, "loc5");
  expect(target.classList.contains("indent")).toBe(true); // fails
});
 

由于className替换整个类的名称,所使用的任何其他类可以有太多删除。

你可以看到在失败的测试以下CodePen 请注意,茉莉花特定代码是在一个单独的笔,发现这里

相反,有这些潜在的问题,我们可以用班级列表添加和删除的类名称。

 // good code
target.classList.add("show");
// ...
target.classList.remove("show");
 

现在,这导致在测试中通过,如可以如下所示:

见笔JRPxjG由SitePoint( @SitePoint上) CodePen

这些改进后生成的代码现在是:

 // improved code
var source = document.getElementById("location");
var target = document.getElementById("second");
var triggerValue = "loc5";

source.addEventListener("change", function () {
  var selectedValue = this[this.selectedIndex].value;
  if (selectedValue === triggerValue) {
    target.classList.add("show");
  } else {
    target.classList.remove("show");
  }
}, false);
 

如果你担心,你想支持IE9和旧浏览器使用班级列表API,你可以改用独立addClass与removeClass功能来实现类似的结果。

结论

提高你的代码不必是硬的或困难的任务。

具体到一般的原则是有益的副作用,即来自测试驱动开发。 不管你是否测试代码或不不过,你也可以受益于这些通用代码技术,使你的代码更加灵活。 这将释放您返回经常来修复你的代码。

尝试在自己的代码工作的一些这些改进,并让我们知道他们是如何改进你的东西-或者在打我们了论坛作进一步讨论和帮助。

From: https://www.sitepoint.com//javascript-refactoring-techniques-specific-to-generic-code/