+!! оператора в выражении if
Я просмотрел код для angularjs factory, чтобы лучше понять, как он работает. Код содержит оператор if
, который я не совсем понимаю.
В демо-версии plnkr автор написал следующее:
if ((+!!config.template) + (+!!config.templateUrl) !== 1) {
throw new Error('Expected modal to have exactly one of either `template` or `templateUrl`');
}
Он немного отличается в репозитории github:
if (!(!config.template ^ !config.templateUrl)) {
throw new Error('Expected modal to have exactly one of either `template` or `templateUrl`');
}
Очевидно, что сообщение об ошибке проверяет наличие одного из двух. Я просто не знаю, как это получается. Я не смог найти информацию о ^
или +!
Мой вопрос: как это работает оператор if? (^
или +!
или +!!
)
Ответы
Ответ 1
!!
преобразует значение в логическое (true
или false
). +
затем преобразует логическое значение в число, либо 1
для true
или 0
для false.
> +true
1
> +false
0
Лично я нахожу более понятным писать что-то вроде этого, имея дело с двумя булевыми:
if (!config.template == !config.templateUrl) {
throw ...
}
Явная и читабельность кода, судя по всему, проклята.
Ответ 2
+!! использует неявное преобразование для приведения значения как 0 или 1 в зависимости от его логического значения
По большей части это проверка на существование. Например, пустая строка имеет значение false (!!"" === false
), и это означает undefined и ряд других. Это основные два, хотя
"Ложные" преобразования
+!!"" === 0
+!!false === 0
+!!0 === 0
+!!undefined === 0
+!!null === 0
+!!NaN === 0
Преобразования "Truthy"
+!!1 === 1
+!!true === 1
+!!"Foo" === 1
+!!3.14 === 1
+!![] === 1
+!!{} === 1
if ((+!! config.template) + (+!! config.templateUrl)! == 1)
Надеюсь, это имеет смысл в этом вопросе. Объект config
имеет два свойства, которые мы рассматриваем. .template
и .templateUrl
. Неявное преобразование в 0 или 1 с помощью +!!
будет добавлено, а затем сравнивается, чтобы убедиться, что оно не равно 1 (что означает, что оно равно 0 или 2). Свойства могут быть либо включенными, либо выключенными, но не различными.
Таблица истинности выглядит следующим образом:
template templateUrl (+!!) + (+!!) !==1
"foo" "foo" 1 + 1 true
undefined undefined 0 + 0 true
undefined "" 0 + 0 true
"" undefined 0 + 0 true
12 "" 1 + 0 false
"" 12 0 + 1 false
undefined "foo" 0 + 1 false
"" "foo" 0 + 1 false
"foo" "" 1 + 0 false
"foo" undefined 1 + 0 false
Более простым методом для всего этого было бы просто использовать неявное булево преобразование
if (!config.template === !config.templateUrl)
Ответ 3
Это ужасно читаемый способ выписать логическое значение переменной, а затем преобразовать его с помощью унарного преобразования, чтобы дать результат 0/1.
Рассмотрим:
+!!true; //this converts true to false, then to true again, and true is 1 when converted
+!!0; //converts 0 (falsy) to true, then false, and then the numeric 0
Технически говоря, !!
не является его собственным оператором, это просто оператор NOT (!
) дважды.
Унарное преобразование: ECMA spec doc унарный плюс пытается преобразовать в целое число. Number()
также будет правильным преобразованием.
Ответ 4
Между тем ^
- побитовый оператор XOR.
При работе с номерами меньше 2, ^
будет работать как логическое ИЛИ (||
), если вы считаете 0
= false
и 1
= true
.
Ответ 5
! является логическим оператором. Это унарный оператор, который преобразует его операнд в логическое и затем отрицает его. !!
- это просто этот оператор дважды, второй !
отменяет отрицание, поэтому конечным результатом является просто преобразование в логическое.
+ - это оператор унарного плюса, который преобразует его в число. В случае логического значения false становится 0
, а true становится 1
.
Итак, +!!(expression)
оценивает 1
, если выражение является правдивым и 0
, если выражение является ложным.
Ответ 6
if ((+!!config.template) + (+!!config.templateUrl) !== 1) {
0 + 0 !== 1 true
0 + 1 !== 1 false
1 + 0 !== 1 false
1 + 1 !== 1 true
равно
if (!config.template === !config.templateUrl) {
несмотря на содержимое двух свойств.