JavaScript Двойное отрицание(!!) и побитовый оператор Тильда (~)

596
11 февраля 2017, 09:36

Изучаю JavaScript. Задачка из учебника:
Напишите функцию checkSpam(str), которая возвращает true, если строка str содержит „html“ или „css“, а иначе false. Функция должна быть нечувствительна к регистру:

Ответ из учебника:

function checkSpam(str) { 
  var lowerStr = str.toLowerCase(); 
 
  return !!(~lowerStr.indexOf('html') || ~lowerStr.indexOf('css')); 
} 
 
alert( checkSpam('hTml now') ); 
alert( checkSpam('free cSs') ); 
alert( checkSpam("more java") );

Вопросы:

  1. Меня путает наличие сразу !! и ~
    Как читается строка return? "Если не найдено, то вернуть ..."
    первый знак ! = Не, и приводим к логическому типу; дальше непонятки из-за ~ и второго отрицания.
  2. Вот мой вариант, он мне кажется понятнее:

function checkSpam(str) { 
	var lowerStr = str.toLowerCase(); 
	return (lowerStr.indexOf('html') != -1 || lowerStr.indexOf('css') != -1); 
} 
alert( checkSpam('hTml now') ); 
alert( checkSpam('free cSs') ); 
alert( checkSpam("more java") );

Есть ли в данных вариантах разница и какой вид более предпочтительный?

Answer 1

Знак ! обозначает не.

Если вы напишите return (~lowerStr.indexOf('html') || ~lowerStr.indexOf('css')), то оно просто выведет положение слов.
Если вы введёте return !(~lowerStr.indexOf('html') || ~lowerStr.indexOf('css')), но оно выведет true/false, при том, что false выведется, если слово было найдено
А когда вы вводите два !!, то оно выведет true, там где было false и наоборот

Знак ~ возвращает значение -(число + 1).
Т.е. в вашем случае, если положение равно -1, то она выводит 0 и при этом в условии выводится false, а если другое любое число, то это true

Answer 2

Вы столкнулись с "магией операторов". В данном случае операторы применяются для следующего:

  1. Оператор ~ возвращает 0 для -1 и не 0 для всего остального. Поэтому в булевом контексте оператор ~ делает почти то же самое, что и сравнение != -1.

  2. Оператор !! (на самом деле это два оператора), который вы правильно назвали двойным отрицанием, преобразует любое значение в булево. Этот оператор нужен только потому что оператор ~ возвращает число, если бы там было сравнение - то и двойное отрицание бы не понадобилось.

Таким образом, вы совершенно правильно написали return (lowerStr.indexOf('html') != -1 || lowerStr.indexOf('css') != -1);. Ваш вариант делает в точности то же самое, что и строка из учебника, только написан понятнее.

Можно даже убрать скобки:

return lowerStr.indexOf('html') != -1 || lowerStr.indexOf('css') != -1;

Именно так и надо писать если ваш код будет читать кто-то, кроме вас самих. Если же вы пишите так называемый "write-only" код - иногда имеет смысл использовать "магические" сокращения если это ускоряет его написание.

READ ALSO
Оптимизация Canvas

Оптимизация Canvas

Здравствуйте, начал изучать canvas ,но столкнулся с проблемой оптимизацииИскал инфу но так и не понял что именно нужно делать

367
JS. выдает предупреждение closure-compiler на document.onmousemove = null;

JS. выдает предупреждение closure-compiler на document.onmousemove = null;

Здравствуйте, почему closure-compiler бросает предупреждения (warning) если я отменяю события с помощью documentonmousemove = null; Значит я что-то делаю не по этикету?

286
Content Security Policy, mod_pagespeeds и unsafe-inline

Content Security Policy, mod_pagespeeds и unsafe-inline

Добрый день, сообщество! Пытаюсь внедрить CPS на сайтеНа сервере установлен mod_pagespeeds, который, к моему удивлению, генерит кучу eval на странице

380
Задать блоку display: none;, когда он вне поля экрана?

Задать блоку display: none;, когда он вне поля экрана?

И показывать блок заблаговременно до границы экрана, что сверху, что снизу

281