【问题标题】:Best practices for testing / checking strings in JavaScript在 JavaScript 中测试/检查字符串的最佳实践
【发布时间】:2021-09-30 05:39:15
【问题描述】:

我最近遇到了这个(不可否认的)教科书 JavaScript 练习,我在概念上遇到了困难,我被告知是“最佳实践”的两个解决方案。我意识到这是非常基本的东西;我只是想尽可能地牢牢掌握这里的基础知识。

练习本身很简单:编写一个函数来检查一个字符串是否包含相同数量的两个唯一字符(在本例中为“x”和“o”)。该函数必须返回一个布尔值并且不区分大小写。

我部分理解的第一个“最佳实践”解决方案是:

function XO(string) {
let x = str.match(/x/gi);
let o = str.match(/o/gi);
return (x && x.length) === (o && o.length);
}

我了解函数的前两行中正在完成的基本正则表达式工作,但 && 逻辑运算符在函数的第三行 & 最后一行中的确切作用让我感到困惑。我很难用简单的英语向自己解释 (a) 它的作用以及 (b) 为什么在这种情况下,像 return x === y 这样的东西本身并不是一个足够强大的解决方案。

我遇到的第二个“最佳实践”解决方案是这样的:

const XO = str => {
  str = str.toLowerCase().split('');  
  return str.filter(x => x === 'x').length === str.filter(x => x === 'o').length;
}

恐怕我不得不承认这个解决方案的大部分逻辑都让我无法理解,尽管我确实知道 .split('') 正在运行以生成可以通过 .filter 运行的单个字符数组。

【问题讨论】:

  • sigh 没错。我已经编辑了原始帖子以删除这个(明显的)错误。正则表达式让我在日落后对视。
  • 两者都只计算字符串中x和o(或y)的数量
  • 确实有人告诉过我。不幸的是,我无法用简单的英语向自己解释为什么 (x && x.length) === (o && o.length) 在这里是必要的。对于像 'xxxooo' 这样的字符串,x='xxx'、o = 'ooo'、x.length = 3 和 o.length = 3?如果是这样,为什么将所有四个值都合并到函数的最后一行?我猜我错过了某种边缘猜测?或者也许是我不熟悉的 JS 最佳实践?

标签: javascript arrays regex arrow-functions boolean-expression


【解决方案1】:

首先,match 返回 null 如果根本没有匹配。如果你尝试取null的长度,会报错。

x && x.length 有效,因为 a) 运算符短路:如果前者是“假的”,则不执行后者(它不会改变结果)并且 返回最后一个真值, b) 在布尔上下文中任何值都被强制为布尔值(例如,作为 && 的操作数)

function XO(string) {
  let x = str.match(/x/gi); 
  // x contains an array that has every match if any
  // e.g. ["x", "x", "x"] or null

  let o = str.match(/o/gi);
  // same for "o"

  return (x && x.length) === (o && o.length);
  // 
  // Given x === null, y === null : 
  //   (null && null.length) === (null && null.length)
  //   (false && null.length) === (false && null.length) <- boolean coercion
  //   false === false
  //   true
  // 
  // Given x === ["x", "x"], y === ["y", "y"] : 
  //   (["x", "x"] && ["x", "x"].length) === (["y", "y"] && ["y", "y"].length)
  //   (true && ["x", "x"].length) === (true && ["y", "y"].length)
  //   (true && 2) === (true && 2)
  //   2 === 2
  //   true
}

第二个有其他技巧。它使用输入参数作为变量(这不太常见,但有效)。此外,它使用“箭头函数”而不是常规函数。它们有一些区别,但大多数情况下你可以认为function a(x) { return 2*x; }const a = (x) =&gt; 2*x; 一样工作

const XO = str => {
  str = str.toLowerCase().split(''); 
  // replace the argument string with an array of characters
  //   str = "xXyY".toLowerCase().split('')
  //   str = "xxyy".split("")
  //   str = ["x", "x", "y", "y"]

  return str.filter(x => x === 'x').length === str.filter(x => x === 'o').length;
  //   ["x", "x", "y", "y"].filter(x => x === 'x').length === ["x", "x", "y", "y"].filter(x => x === 'y').length;
  //   ["x", "x"].length === ["y", "y"].length
  //   2 === 2
  //   true
}

【讨论】:

  • GRMA 萨米!这正是我正在寻找的那种彻底的解释/细分!非常感谢您抽出宝贵时间帮助我填写缺失的部分;这对我来说非常清楚。
猜你喜欢
  • 1970-01-01
  • 2010-11-10
  • 1970-01-01
  • 1970-01-01
  • 2020-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-29
相关资源
最近更新 更多