跳到内容

JavaScript/最佳实践

来自维基教科书,开放世界中的开放书籍



本章将介绍当前 JavaScript 社区的标准和最佳实践,每个程序员都应该知道。

document.write

[编辑 | 编辑源代码]

此方法已过时。请改用 innerHTML 或 DOM 操作方法。

在 XHTML 中,document.write 不起作用,但您可以使用 DOM 操作方法来实现相同的效果[1].

JavaScript 协议

[编辑 | 编辑源代码]

尝试避免仅用于执行 JavaScript 代码的链接。

<a href="javascript:resumeFancyVersion()">See my résumé!</a>

相反,考虑

<a href="resumePlainVersion.html" onclick="return !resumeFancyVersion()">See my résumé!</a>

启用 JavaScript 的用户将获得包含 JavaScript 增强内容的版本(可能使用 DHTML),而未启用 JavaScript 的用户将被重定向到以静态方式提供此内容的 XHTML 页面。这比使用没有正常 href 属性值的 <a> 元素更易于访问。首先,它使用 正确的语言语义。其次,它为没有 JavaScript 的用户提供访问内容的途径。第三,它检测函数执行是否成功,并在失败的情况下也重定向支持 JavaScript 的读者。

onclick 表达式计算为布尔值。如果函数成功执行所需的效果并返回 true,onclick 将返回失败,并且超链接不会执行。当函数由于任何原因失败时,false、null 或 undefined 值将计算为 true,并且不会阻止链接执行。或者,如果您不想提供静态等效项,您可以在语义要求不高的元素内嵌入 onclick 属性

<strong onclick="resumeFancyVersion()">See my résumé!</strong>

因此,任何用户代理在阅读简化的 <a> 元素时都不会感到困惑。

电子邮件验证

[编辑 | 编辑源代码]

许多人使用 JavaScript 函数来立即捕获表单输入中最常见的错误类型。例如,一些网页表单要求人们两次输入相同的内容。其他网页表单要求人们输入电子邮件地址。然后,他们快速检查一下输入的内容是否至少看起来有点像电子邮件地址

function isValidEmail(string) {
  // These comments use the following terms from RFC2822:
  // local-part, domain, domain-literal and dot-atom.
  // Does the address contain a local-part followed an @ followed by a domain?
  // Note the use of lastIndexOf to find the last @ in the address
  // since a valid email address may have a quoted @ in the local-part.
  // Does the domain name have at least two parts, i.e. at least one dot,
  // after the @? If not, is it a domain-literal?
  // This will accept some invalid email addresses
  // BUT it doesn't reject valid ones.
  var atSym = string.lastIndexOf("@");
  if (atSym < 1) { return false; } // no local-part
  if (atSym == string.length - 1) { return false; } // no domain
  if (atSym > 64) { return false; } // there may only be 64 octets in the local-part
  if (string.length - atSym > 255) { return false; } // there may only be 255 octets in the domain

  // Is the domain plausible?
  var lastDot = string.lastIndexOf(".");
  // Check if it is a dot-atom such as example.com
  if (lastDot > atSym + 1 && lastDot < string.length - 1) { return true; }
  // Check if could be a domain-literal.
  if (string.charAt(atSym + 1) == '[' && string.charAt(string.length - 1) == ']') { return true; }
  return false;
}

不幸的是,一些其他“电子邮件验证”JavaScript 函数会拒绝完全有效的电子邮件地址。例如,一些 错误地拒绝 包含“+”号的有效地址。

原始电子邮件地址语法(RFC 821)确实允许“+”号。 RFC 822 于同一个月(1982 年 8 月)发布,也允许它们。当前版本的语法在 RFC2821/RFC2822 中给出。RFC3696 的第 3 节给出了非同寻常的有效电子邮件地址的实用示例。

验证后,许多 JavaScript 程序员使用 encodeURIComponent() 对电子邮件地址进行编码,以解决某些客户端语言似乎无法正确处理加号的问题。[1][2]

用于电子邮件地址的引用规则的复杂性使得对地址的本地部分或域文字进行完整测试变得不切实际。鉴于不一定存在与有效本地部分相对应的真实邮箱,花多少额外下载时间来执行复杂的验证脚本才值得呢?

根据 RFC2822 有效的示例

[编辑 | 编辑源代码]

根据 RFC2822s 无效的示例

[编辑 | 编辑源代码]

测试页面

[编辑 | 编辑源代码]

注释:此代码设计不当,会拒绝某些实际上有效的电子邮件。如果对有效和无效电子邮件的更改被接受,则应同时检查以下代码。

以下测试页面可用于测试电子邮件验证函数。将三个文件保存在同一目录中,然后在网页浏览器中打开 validEmail.htm

validEmail.js

function isValidEmail(string) {
  // These comments use the following terms from RFC2822:
  // local-part, domain, domain-literal and dot-atom.
  // Does the address contain a local-part followed an @ followed by a domain?
  // Note the use of lastIndexOf to find the last @ in the address
  // since a valid email address may have a quoted @ in the local-part.
  // Does the domain name have at least two parts, i.e. at least one dot,
  // after the @? If not, is it a domain-literal?
  // This will accept some invalid email addresses
  // BUT it doesn't reject valid ones.
  var atSym = string.lastIndexOf("@");
  if (atSym < 1) { return false; } // no local-part
  if (atSym == string.length - 1) { return false; } // no domain
  if (atSym > 64) { return false; } // there may only be 64 octets in the local-part
  if (string.length - atSym > 255) { return false; } // there may only be 255 octets in the domain

  // Is the domain plausible?
  var lastDot = string.lastIndexOf(".");
  // Check if it is a dot-atom such as example.com
  if (lastDot > atSym + 1 && lastDot < string.length - 1) { return true; }
  //  Check if could be a domain-literal.
  if (string.charAt(atSym + 1) == '[' && string.charAt(string.length - 1) == ']') { return true; }
  return false;
}

function testIsValidEmail(string) {
  alert("'" + string + "' is " + (isValidEmail(string) ? "" : "NOT ") + " a valid email address.");
}

function checkSamples() {
  var validAddress = [
    '[email protected]',
    '[email protected]',
    '[email protected]',
    'name\\@[email protected]',
    'spaces\\ are\\ [email protected]',
    '"spaces may be quoted"@example.com',
    '!#$%&\'*+-/=.?^_`{|}~@[1.0.0.127]',
    '!#$%&\'*+-/=.?^_`{|}~@[IPv6:0123:4567:89AB:CDEF:0123:4567:89AB:CDEF]',
    'me(this is a comment)@example.com'
  ];
  var invalidAddress = [
    'me@',
    '@example.com',
    '[email protected]',
    '[email protected]',
    '[email protected]',
    'me.example@com',
    'me\\@example.com'
  ];

  var results = new StringBuffer();

  var handlesValidAddressesCorrectly = true;
  results.append('<table border="1">');
  results.append('<caption>Does the function accept all the valid sample addresses?</caption>');
  results.append('<tr><th>Valid address</th><th>Function returns</th></tr>');
  for (var i = 0; i < validAddress.length; i++) {
    results.append('<tr><td>');
    results.append(validAddress[i]);
    results.append('</td><td>');
    if (isValidEmail(validAddress[i])) {
      results.append('<span class="good">true</span>');
    } else {
      handlesValidAddressesCorrectly = false;
      results.append('<strong class="fail">false</strong>');
    }
    results.append('</td></tr>');
  }
  results.append('</table>');

  var handlesInvalidAddressesCorrectly = true;
  results.append('<table border="1">');
  results.append('<caption>Does the function reject all the invalid sample addresses?</caption>');
  results.append('<tr><th>Valid address</th><th>Function returns</th></tr>');
  for (var i = 0; i < invalidAddress.length; i++) {
    results.append('<tr><td>');
    results.append(invalidAddress[i]);
    results.append('</td><td>');
    if (!isValidEmail(invalidAddress[i])) {
      results.append('<span class="good">false</span>');
    } else {
      handlesInvalidAddressesCorrectly = false;
      results.append('<em class="warning">true</em>');
    }
    results.append('</td></tr>');
  }
  results.append('</table>');

  var conclusion;
  if (handlesValidAddressesCorrectly) {
    if (handlesInvalidAddressesCorrectly) {
      conclusion = '<p><strong class="good">The function works correctly with all the sample addresses.</strong></p>';
    } else {
      conclusion = '<p><em class="warning">The function incorrectly accepts some invalid addresses.</em></p>';
    }
  } else {
    conclusion = '<p><strong class="fail">The function incorrectly rejects some valid addresses.</strong></p>';
  }

  document.getElementById('testResults').innerHTML = conclusion + results.toString();
}

function StringBuffer() {
  this.buffer = "";
}

StringBuffer.prototype.append = function(string) {
  this.buffer += string;
  return this;
};

StringBuffer.prototype.toString = function() {
  return this.buffer;
};

validEmail.css

body {
  background-color: #fff;
  color: #000
}

table {
  margin-bottom: 2em
}

caption {
  margin-top: 2em
}

.good {
  background-color: #0f0;
  color: #000
}

.warning {
  background-color: #fc9;
  color: #000
}

.fail {
  background-color: #f00;
  color: #fff
}

validEmail.htm

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Valid email test</title>
    <link rel="stylesheet" href="validEmail.css">
    <script src="validEmail.js"></script>
  </head>
  <body onload="checkSamples()">
    <h1>Unit test for email address validation functions</h1>
    <h2>Interactive test</h2>
    <form action="#">
      <fieldset>
        <legend>Email address</legend>
        <label for="emailAddress">Email</label>
        <input type="text" size="40" value="" name="email" id="emailAddress">
        <input type="button" name="validate" value="Check address"
          onclick="testIsValidEmail(this.form.email.value)">
      </fieldset>
    </form>
    <h2>Selected samples</h2>
    <p>This section shows the results of testing the function with sample strings.
      The sample includes both valid strings and invalid strings
      according to <a href="http://www.faqs.org/rfcs/rfc2822.html">RFC2822</a>.
    </p>
    <div id="testResults">You need to enable JavaScript for this unit test to work.</div>
  </body>
</html>

use strict

[编辑 | 编辑源代码]

许多 JavaScript 程序员建议通过在任何其他语句之前放置精确语句 "use strict"; 来启用 ECMAScript 5 的严格模式:[3][4][5]

  "use strict";
  function 

进一步阅读

[编辑 | 编辑源代码]

JavaScript 最佳实践

其他语言中的最佳实践

[编辑 | 编辑源代码]

参考文献

[编辑 | 编辑源代码]
华夏公益教科书