
Прежде всего нужно понять «Истину», как она представлена в таблице истинности. На самом деле таких таблиц несколько, но для этого урока нам хватит двух — AND и OR. Начнём.
AND
Обозначается как &. В этом случае сравнение двух битов, A и B, даст результат 1 только тогда, когда оба A и B равны 1.

С помощью приведённой выше таблицы легко определить результат побитовой операции AND между двумя целыми числами. Например, чтобы найти результат 12 & 4, преобразуйте оба числа в их двоичные представления:
- 12 = 1100
- 4 = 100
Так-так. 12 имеет четыре бита, а 4 всего три бита. В таком случае можно сделать их одинаковой длины, добавив 0 туда, где меньше битов. 4 = 0100.
Теперь, когда числа одинаковой длинны, мы можем произвести операцию:
1100 &0100 = 0100
Начиная с самого правого бита каждого числа, сверяясь с таблицей выше, найдите все значения. Итак, у нас получается 0&0=0, 0&0=0, 1&1=1 и 1&0=0. Результат 0100, т.е. 4, значит 12&4 = 4.
OR
Обозначается как |. Здесь, сравнение двух битов, A и B, даст результат 1, если хотя бы один бит (A или B) равен 1.

С помощью этой таблицы можно определить результат побитовой операции OR между двумя целыми числами.
Например, чтобы найти результат 13|3, снова преобразуем целые числа в двоичное представление:
- 13 = 1101
- 3 = 11
Добавляем нули: 3 = 0011.
Вычисляем OR:
1101 |0011 =1111
Сопоставляем каждый бит, начиная справа, с таблицей выше, чтобы найти соответствующее значение. Итак, у нас получается 1|1=1, 0|1=1, 1|0=1 и 1|0=1. Результат 1111, т.е. 15, значит 13|3=15.
Чем это может быть полезно?
Представьте, что вам нужно написать функцию, которая принимает строку и возвращает строку декоратор в окружении какого-либо из следующих тегов: <i>, <b>, и <u>.
Вариант 1
Мы можем написать функцию, которая учитывает все теги в своей подписи. Тогда у нас получится что-то вроде этого:
function decorateString1(str, includeITag, includeBTag, includeUTag) { let result = str; if (includeITag) { result = '<i>' + result + '</i>'; } if (includeBTag) { result = '<b>' + result + '</b>'; } if (includeUTag) { result = '<u>' + result + '</u>'; } return result; } console.log(decorateString("Hello", true)) /* <i>Hello</i> */ console.log(decorateString("Hello", true, true)) /* <b><i>Hello</i></b> */ console.log(decorateString("Hello", true, true, true)) /* <u><b><i>Hello</i></b></u> */
Данная функция работает хорошо. Сложность этого варианта заключается в том, что вы должны запомнить расположение каждого тега при передаче аргументов в функцию.
Кроме того, предположим, что вы просто хотите подчеркнуть текст. Вам придётся сделать что-то вроде этого: decorateString(«Hello», false, false, true). Любой, кто будет читать этот код (кроме вас), должен будет найти функцию и посмотреть, что в ней, чтобы узнать, что является false, а что true.
Вариант 2
Вообще-то вам не нужно писать функцию таким способом в Javascript. Вы можете сделать второй аргумент объектом и деструктурировать его, чтобы получить доступ к значениям и работать с ними. Вот так:
function decorateString(str, style) { const {includeITag, includeBTag, includeUTag} = style || {}; let result = str; if (includeITag) { result = '<i>' + result + '</i>'; } if (includeBTag) { result = '<b>' + result + '</b>'; } if (includeUTag) { result = '<u>' + result + '</u>'; } return result; } console.log(decorateString("Hello", {includeUTag: true})); /* <u>Hello</u> */
Так намного лучше, так как мне не нужно запоминать порядок тегов, а только указывать те, которые я хочу. Но я не использую Javascript. Есть ещё варианты?
Вариант 3
Вариант есть. Давайте представим, что бит представляет собой флаг. Когда бит равен 1, флаг поднимается, когда бит равен 0, флаг опускается. Теперь у каждого тега будет флаг в определенной позиции. Мы можем определить каждый из тегов следующим образом (в двоичном формате):
includeITag = 001 // 1 includeBTag = 010 // 2 includeUTag = 100 // 4
Вызов функции будет выглядеть так:
- Чтобы включить только тег I: decorateString(«Hello», 1)
- Чтобы включить только тег B: decorateString(«Hello», 2)
- Чтобы включить только тег U: decorateString(«Hello», 4)
Неплохо, но мне придётся запоминать эти цифры. Верно?
На самом деле нет. Эти значения будут определены как константы в классе/файле, который содержит эту функцию, поэтому вам не нужно их запоминать.
Но нет никакого способа использовать два тега вместе. Чтобы строка включала теги I и B, нам нужно установить два флага, т.е. 011. А чтобы включить три тега, нам нужно 111.
Т.е. нам нужно определять значения для всех возможных комбинаций тегов? Нет. Вы создаёте только те, которые вам нужны, и генерируете комбинации. В этом нам пригодится оператор |.
includeITag | // 001 includeBTag // 010 // 011
Теперь мы можем вызывать функцию так:
Чтобы включить только I и B теги: decorateString(«Hello», includeITag | includeBTag)
Чтобы включить три тега: decorateString(«Hello», includeITag | includeBTag | includeUTag)
Использовать можно в любом порядке.
Как же тогда извлечь эти значения из входных данных? Проверяя, установлен ли флаг! В этом нам поможет оператор &.
Чтобы проверить, установлен ли бит в индекс i, нужно проверить значение индекса 2^i через AND. Если результат не равен 0, то бит установлен, иначе бит не установлен.
Например, нужно проверить 1101, установлен ли бит с индексом 1: 2¹=2. Получается:
1101 & 0010 = 0000
Так как это 0, бит в индексе 1 не установлен. А если так же проверить 1011:
1011 & 0010 = 0010
Так как результат не равен 0, значит бит в индексе 1 установлен. Теперь мы можем создать такую функцию:
const includeITag = 0b001; // 1 const includeBTag = 0b010; // 2 const includeUTag = 0b100; // 4 function decorateString(str, styleFlag) { let result = str; if ((styleFlag & includeITag) !== 0) { result = '<i>' + result + '</i>'; } if ((styleFlag & includeBTag) !== 0) { result = '<b>' + result + '</b>'; } if ((styleFlag & includeUTag) !== 0) { result = '<u>' + result + '</u>'; } return result; } console.log(decorateString("Hello", includeBTag | includeUTag)); /* <u><b>Hello</b></u> */ console.log(decorateString("Hello", includeUTag)); /* <u>Hello</u> */
Это можно реализовать в любом языке программирования, без деструктуризации или передачи длинного списка параметров. Пример использования такого подхода — установка флагов при запуске нового Activity в Android:
myIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION|Intent.FLAG_ACTIVITY_CLEAR_TOP);
Специально для сайта ITWORLD.UZ. Новость взята с сайта NOP::Nuances of programming