Ответ 1
Вы можете отфильтровать Object.values и проверить, равна ли длина 1
let obj = {
a: true,
b: false,
c: false
};
let oneTrue = Object.values(obj).filter(e => e === true).length === 1;
console.log(oneTrue);
Я хочу проверить объект, который имеет три булевых свойства, один и только один, должны быть истинными. Каков наилучший способ проверить это?
Я придумал это:
var t1 = obj.isFirst ? 1 : 0,
t2 = obj.isSecond ? 1 : 0,
t3 = obj.isThird ? 1 : 0;
var valid = (t1 + t2 + t3) === 1;
Это прекрасно работает, но это немного похоже на решение для любителей :-)
Есть ли лучший способ сделать это? Например, используя XOR (^)?
Вы можете отфильтровать Object.values и проверить, равна ли длина 1
let obj = {
a: true,
b: false,
c: false
};
let oneTrue = Object.values(obj).filter(e => e === true).length === 1;
console.log(oneTrue);
Вы можете использовать array.reduce:
var obj = {
a: true,
b: false,
c: false
};
var res = Object.values(obj).reduce((m, o) => m + o) === 1;
console.log(res);
Использование:
obj.isFirst + obj.isSecond + obj.isThird === 1
Если предположить, что значения являются булевыми, а не чем-то другим. Вы можете добавить явное преобразование, если хотите:
Number(obj.isFirst) + Number(obj.isSecond) + Number(obj.isThird) === 1
Но JavaScript также неявно делает это преобразование для вас.
(Это основано на комментарии ASDFGerte.)
Если обратиться к проблеме с другой стороны, похоже, вы пытаетесь смоделировать то, что может иметь 3 возможных состояния. Не представляйте его как 3 булева, представляйте его как переменную с тремя возможными значениями:
const STATES = ['STATE_A', 'STATE_B', 'STATE_C'];
let value = 'STATE_A';
Если вы хотите использовать одно из булевых:
doSomethingDependingOnBooleanC(value === 'STATE_C');
Если вы хотите подтвердить, что это value
ожидаемому (одно из трех возможных состояний):
const isValid = STATES.includes(value);
const isValidInOlderBrowsers = STATES.indexOf(value) !== -1;
Вы можете сделать это в одной строке, но читать ее нелегко. Но если обфускация - ваша цель, читайте дальше.
Поскольку obj.isFirst
, obj.isSecond
и obj.isThird
- все либо 0
либо 1
, вы можете использовать побитовый оператор XOR ^
между ними:
(obj.isFirst ^ obj.isSecond ^ obj.isThird) ^ (obj.isFirst && obj.isSecond && obj.isThird)
Нам нужно XOR против obj.isFirst && obj.isSecond && obj.isThird
потому что obj.isFirst ^ obj.isSecond ^ obj.isThird
оценивает значение true
.
Как насчет:
var valid = (obj.isFirst + obj.isSecond + obj.isThird) === 1;
Примечание. Возврат суммы является целым числом, и он переводит true в 1 и false в 0. Таким образом, вам не нужно boolValue? 1: 0
boolValue? 1: 0
См. Этот набор результатов для справки:
console.log(true + false + false) // 1
console.log(false + false + false) // 0
console.log(false + false + true) // 1
console.log(1 + false + 0) // 1
console.log(false + 1 + 1) // 2
Также позвольте мне указать, если вы хотите, чтобы явное преобразование и ваши данные были строковыми, вы можете столкнуться с этой проблемой. Итак, я бы предпочел использовать Boolean
чем Number
.
var a = "true",
b = false,
c = false;
var valid = Number(a) + Number(b) + Number(c);
console.log(valid); // NaN
var a = "true",
b = false,
c = false;
var valid = Boolean(a) + Boolean(b) + Boolean(c);
console.log(valid); // 1
Оберните его в функцию с именем "обеспечитьOnlyOnePropertyIsTruthy". Возьмите список имен свойств вместе с объектом и всякий уродливый, исполняемый код, который вы хотите внутри. Никто не должен будет читать внутренности, потому что ваша функция дает им единственный необходимый контекст.
Для чего-то чуть менее загадочного:
var valid = obj.isFirst ? !(obj.isSecond || obj.isThird) : (obj.isSecond ^ obj.isThird)