[JavaScript] Внимание, подводный камень
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Я только что нашёл очень незаметный баг в своём коде, и хочу поделиться им.
Задача
Дан список строк: VALID_STRINGS.
Cоздать функцию test(x) которая должна вернуть true, если x — это одна из строк в этом массиве.
Решение №1: Решение в лоб
Самым простым решением, которое может быть — это пройтись по всем строкам в этом массиве и сравнить.
const VALID_STRINGS = [/* VALID STRINGS */]
function test1(x) {
for (const string of VALID_STRINGS) {
if (string === x) return true
}
return false
}
Это решение правильное, но медленное, потому что оно заставляет при каждом вызове функции пробегать по массиву в поисках совпадения. Таким образом сложность алгоритма по времени будет O(длина массива VALID_STRINGS)
Решение №2: Словарь
Массив не очень подходящая структура данных для подобной проверки. Куда лучше использовать словарь для хранения валидных строк. Ведь доступ к элементу словаря по ключу выполняется за константное время.
const VALID_STRINGS = [/* VALID STRINGS */]
const VALID_STRINGS_DICT = {}
for (const string of VALID_STRINGS) {
VALID_STRINGS_DICT[string] = true
}
function test2(x) {
return VALID_STRINGS_DICT[x] === true
}
Отличное решение за константное время!
Берегись! Подводный камень!
Это хоть и быстрое решение, но не правильное. Оно не гарантирует того, что х — будет элементом массива VALID_STRINGS. И чтобы это продемонстрировать приведу контрпример:
// Предположим
const VALID_STRINGS = ['somestring', 'anotherstring']
// Тогда после заполнения словаря, он будет иметь следующий вид
const VALID_STRINGS_DICT = { somestring: true, anotherstring: true }
const underwaterRock = ['somestring']
test2(underwaterRock) // вернёт true
Хоть underwaterRock и не является строкой — но наша функция вернула true. А всё потому, что внутри тела функции test2(x) происходит использование x в качестве ключа.
VALID_STRINGS_DICT[x]
В этот момент — x приводится к строковому значению. И в этом и есть проблема — массив приводится к строке путем перечисления своих значений через запятую. Но когда это массив из одного строкового значения — он приводится в точности к своему первому элементу.
['somestring'].toString() === 'somestring'
Решение №3: С дополнительной проверкой
Добавим проверку типа прежде чем использовать x в качестве ключа
const VALID_STRINGS = [/* VALID STRINGS */]
const VALID_STRINGS_DICT = {}
for (const string of VALID_STRINGS) {
VALID_STRINGS_DICT[string] = true
}
function test2(x) {
return typeof x === 'string' && VALID_STRINGS_DICT[x] === true
}
Дополнительная операция, но результат правильный.
Вывод
Спасибо за внимание, и будьте аккуратны, обращайте внимание на весь спектр входных значений ваших задач.
===========
Источник:
habr.com
===========
Похожие новости:
- [JavaScript, Node.JS, Разработка веб-сайтов] Выбор зависимостей JavaScript
- [JavaScript, VueJS, Программирование, Расширения для браузеров] Пишем свой плагин для VueJS. Как проект на VueJS трансформировать в расширение для браузера?
- [JavaScript, Node.JS] Создание Discord-бота, используя библиотеку discord.js | Часть №2 | Аргументы
- [JavaScript, Программирование, Разработка веб-сайтов] Работа с файлами в JavaScript
- [JavaScript, ReactJS, Разработка веб-сайтов] Debouncing с помощью React Hooks: хук для функций
- [JavaScript, Разработка мобильных приложений, Разработка под Android] Как подружить React Native и Java код на Android
- [API, JavaScript, VueJS, Учебный процесс в IT] Онлайн-митап сообщества разработчиков MSK VUE.JS
- [JavaScript, PHP, Ненормальное программирование, Программирование, Разработка веб-сайтов] Inertia.js – современный монолит
- [JavaScript, MongoDB, Node.JS, Высокая производительность] Node.js + MongoDB: перформанс транзакций
- [JavaScript, Open source, Программирование] Объектно-ориентированная альтернатива jquery
Теги для поиска: #_javascript, #_javascript, #_bug, #_validation, #_javascript
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 23-Ноя 05:09
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Я только что нашёл очень незаметный баг в своём коде, и хочу поделиться им. Задача Дан список строк: VALID_STRINGS. Cоздать функцию test(x) которая должна вернуть true, если x — это одна из строк в этом массиве. Решение №1: Решение в лоб Самым простым решением, которое может быть — это пройтись по всем строкам в этом массиве и сравнить. const VALID_STRINGS = [/* VALID STRINGS */]
function test1(x) { for (const string of VALID_STRINGS) { if (string === x) return true } return false } Это решение правильное, но медленное, потому что оно заставляет при каждом вызове функции пробегать по массиву в поисках совпадения. Таким образом сложность алгоритма по времени будет O(длина массива VALID_STRINGS) Решение №2: Словарь Массив не очень подходящая структура данных для подобной проверки. Куда лучше использовать словарь для хранения валидных строк. Ведь доступ к элементу словаря по ключу выполняется за константное время. const VALID_STRINGS = [/* VALID STRINGS */]
const VALID_STRINGS_DICT = {} for (const string of VALID_STRINGS) { VALID_STRINGS_DICT[string] = true } function test2(x) { return VALID_STRINGS_DICT[x] === true } Отличное решение за константное время! Берегись! Подводный камень! Это хоть и быстрое решение, но не правильное. Оно не гарантирует того, что х — будет элементом массива VALID_STRINGS. И чтобы это продемонстрировать приведу контрпример: // Предположим
const VALID_STRINGS = ['somestring', 'anotherstring'] // Тогда после заполнения словаря, он будет иметь следующий вид const VALID_STRINGS_DICT = { somestring: true, anotherstring: true } const underwaterRock = ['somestring'] test2(underwaterRock) // вернёт true Хоть underwaterRock и не является строкой — но наша функция вернула true. А всё потому, что внутри тела функции test2(x) происходит использование x в качестве ключа. VALID_STRINGS_DICT[x]
В этот момент — x приводится к строковому значению. И в этом и есть проблема — массив приводится к строке путем перечисления своих значений через запятую. Но когда это массив из одного строкового значения — он приводится в точности к своему первому элементу. ['somestring'].toString() === 'somestring'
Решение №3: С дополнительной проверкой Добавим проверку типа прежде чем использовать x в качестве ключа const VALID_STRINGS = [/* VALID STRINGS */]
const VALID_STRINGS_DICT = {} for (const string of VALID_STRINGS) { VALID_STRINGS_DICT[string] = true } function test2(x) { return typeof x === 'string' && VALID_STRINGS_DICT[x] === true } Дополнительная операция, но результат правильный. Вывод Спасибо за внимание, и будьте аккуратны, обращайте внимание на весь спектр входных значений ваших задач. =========== Источник: habr.com =========== Похожие новости:
|
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 23-Ноя 05:09
Часовой пояс: UTC + 5