Всё просто: побитовые операторы в js работают только со знаковыми (signed) целыми (integer) длиной в 32 бита (оператор >>> работает с unsigned). Иными словами, побитовые операторы интерпретируют операнды как последовательность из 32 битов.
Т.о., при выполнении ~3 число 3 представляется в виде 0000 0000 0000 0000 0000 0000 0000 0011, результат, понятное дело 1111 1111 1111 1111 1111 1111 1111 1100 — это -4. Если крайний левый (знаковый) бит равен 0 — число положительное, если равен 1 — число отрицательное. Максимальное знаковое целое, которое уместится в 32 бита — это 0111 1111 1111 1111 1111 1111 1111 1111, или 2147483647 (по основанию 10). Минимальное 32-bit signed integer — это 1000 0000 0000 0000 0000 0000 0000 0000, или -2147483648.
2147483647 0111 1111 1111 1111 1111 1111 1111 1111
100 0000 0000 0000 0000 0000 0000 0110 0100
5 0000 0000 0000 0000 0000 0000 0000 0101
4 0000 0000 0000 0000 0000 0000 0000 0100
3 0000 0000 0000 0000 0000 0000 0000 0011
2 0000 0000 0000 0000 0000 0000 0000 0010
1 0000 0000 0000 0000 0000 0000 0000 0001
0 0000 0000 0000 0000 0000 0000 0000 0000
-1 1111 1111 1111 1111 1111 1111 1111 1111
-2 1111 1111 1111 1111 1111 1111 1111 1110
-3 1111 1111 1111 1111 1111 1111 1111 1101
-4 1111 1111 1111 1111 1111 1111 1111 1100
-5 1111 1111 1111 1111 1111 1111 1111 1011
-100 1111 1111 1111 1111 1111 1111 1001 1011
-2147483648 1000 0000 0000 0000 0000 0000 0000 0000
~~3.14 // 3
Шаг 1: число приводится к целому и представляется в виде последовательности 0000 0000 0000 0000 0000 0000 0000 0011.
Шаг 2: производится сама побитовая замена 0->1 и 1->0. Получаем 1111 1111 1111 1111 1111 1111 1111 1100, или -4 (по осн. 10).
Шаг 3: производится ~(-4), то бишь получим в итоге 3.
Ну, с нулем всё понятно думаю.