#javascript #arrays #regex #arrow-functions #boolean-expression
Вопрос:
Недавно я столкнулся с этим (по общему признанию) учебным упражнением на JavaScript, и у меня возникли проблемы с концептуальным рассмотрением двух решений, которые, как мне сказали, являются «лучшими практиками». Я понимаю, что это довольно простой материал; Я просто пытаюсь как можно лучше понять основные принципы здесь.
Само упражнение достаточно простое: напишите функцию, которая проверяет, содержит ли строка одинаковое количество двух уникальных символов (в данном случае » x » и «o»). Функция должна возвращать логическое значение и не учитывать регистр.
Первым решением «наилучшей практики», которое я частично понял, было следующее:
function XO(string) {
let x = str.match(/x/gi);
let o = str.match(/o/gi);
return (x amp;amp; x.length) === (o amp;amp; o.length);
}
Я понимаю основную работу с регулярными выражениями, выполняемую в первых двух строках функции, но точная роль логического оператора amp;amp; в третьей и последней строке функции озадачивает меня. Мне трудно на простом английском языке объяснить себе (а), что именно он делает и (б), почему что-то подобное 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
.
Комментарии:
1. вздох , это правильно. Я отредактировал исходный пост, чтобы удалить эту (очевидную) ошибку. Выражения регулярных выражений заставляют меня косить глазами после захода солнца.
2. оба просто подсчитывают количество x и o (или y) в строке
3. Действительно, мне говорили, что они это делают. К сожалению, мне трудно объяснить себе простым английским языком, почему
(x amp;amp; x.length) === (o amp;amp; o.length)
это необходимо здесь. Для строки типа «xxxooo» неx
будет =»xxx»,o
= «ооо»,x.length
= 3, amp;o.length
= 3? Если да, то зачем включать все четыре значения в последнюю строку функции? Я предполагаю, что есть какое-то преимущество, которого мне не хватает? Или, может быть, лучшая практика JS, с которой я не знаком?
Ответ №1:
Во-первых, match
возвращается null
, если совпадений вообще нет. Если вы попытаетесь взять длину null
, будет выдана ошибка.
x amp;amp; x.length
работает из-за а) короткого замыкания оператора: если первое является «ложным», последнее не выполняется (это не изменит результат), и возвращается последнее значение истинности, б) любое значение вводится как логическое в логическом контексте (например, в качестве операнда в amp;amp;)
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 amp;amp; x.length) === (o amp;amp; o.length);
//
// Given x === null, y === null :
// (null amp;amp; null.length) === (null amp;amp; null.length)
// (false amp;amp; null.length) === (false amp;amp; null.length) <- boolean coercion
// false === false
// true
//
// Given x === ["x", "x"], y === ["y", "y"] :
// (["x", "x"] amp;amp; ["x", "x"].length) === (["y", "y"] amp;amp; ["y", "y"].length)
// (true amp;amp; ["x", "x"].length) === (true amp;amp; ["y", "y"].length)
// (true amp;amp; 2) === (true amp;amp; 2)
// 2 === 2
// true
}
У второго есть и другие хитрости. Он использует входной аргумент в качестве переменной (что не слишком распространено, но допустимо). Кроме того, вместо обычных функций он использует «функции со стрелками». У них есть некоторые отличия, но в основном вы можете думать, что function a(x) { return 2*x; }
это работает как const a = (x) => 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
}
Комментарии:
1. ГРМА Сами! Это именно то подробное объяснение / разбивка, которое я искал! Я действительно ценю, что вы нашли время, чтобы помочь мне заполнить недостающие части; это очень многое для меня прояснило.