И несколько параметров

15
function andMultipleExpr(){
  let logicalAnd;
  let i;
  for (i = 0; i < arguments.length; i++){
    logicalAnd =  arguments[i] && arguments[i+1];
  }
  return logicalAnd;
}

console.log(andMultipleExpr(true, true, false, false));

Я ожидаю выполнения этого кода: true && true && false && false, и это должно вернуть false .

Как заставить это работать в JS? Спасибо

Хаким Аса
источник
Я просто колеблюсь. Я хочу быть уверен, что моя идея хорошо сформулирована. Если есть лучший способ, пожалуйста, предложите.
Хаким Аса
Каким должен быть вывод, когда вместо логических значений используются значения Troothy? то есть andMultipleExpr(1, 1, 0, 0)илиandMultipleExpr(1, 1, 1, 1)
Ник Зоум
Кроме того, что должно быть на выходе andMultipleExpr()(вызов функции без параметров)?
Ник Зум
ну, эти случаи также должны быть приняты во внимание. :-)
Хаким Аса

Ответы:

16

Используйте Array.prototype.everyвсе переданные аргументы, чтобы проверить, все ли они истинны;

function andMultipleExpr(...a) {
  if(a.length === 0) return false; // return false when no argument being passed
  return a.every(Boolean);
}

console.log(andMultipleExpr(true, true, false)); // should return false
console.log(andMultipleExpr(true, true, true)); // should return true

Арчи
источник
Может заменить e => e === trueнаBoolean
Ник Зоум
@nickzoum это будет соответствовать всем истинным значениям, OP строго сравнивает true.
Арчи
1
@ Арчи - Нет, они сравнивают правду и ложь. Там нет ===в коде ОП. Ваша everyидея , однако, на месте . Но просто .every(e => e)делает свою работу.
TJ Crowder
@TJCrowder да только что заметил это. Обновил ответ уже. Спасибо :)
Арчи
Если вы добавите вспомогательную функцию: const isTrue = x => x === true(или x => !!xдля всех истинных значений), вы можете сжать свое решение в return arguments.every(isTrue). Который мне кажется просто красивым.
Мбойко
9

Тебе следует

  1. Начните с logicalAndнабораtrue

  2. Использовать logicalAndпри обновлении, а не использовать две записи изarguments

Минимальное изменение:

function andMultipleExpr(){
    let logicalAnd = true; // ***
    let i;
    for (i = 0; i < arguments.length; i++){
        logicalAnd = logicalAnd && arguments[i]; // ***
    }
    return logicalAnd;
}
console.log(andMultipleExpr(true, true, false, false));

Но у решения mbojko есть преимущество короткого замыкания (остановка цикла, когда он впервые находит ложное значение), что кажется хорошей идеей.

Поскольку вы используете ES2015 +, вам, вероятно, следует использовать параметр rest, а не arguments, и вы можете использовать for-ofцикл:

function andMultipleExpr(...flags) {
    let logicalAnd = true;
    for (const flag of flags) {
        logicalAnd = logicalAnd && flag;
    }
    return logicalAnd;
}
console.log(andMultipleExpr(true, true, false, false));

Вы также можете замкнуть, что в соответствии с подходом Мбойко

function andMultipleExpr(...flags) {
    for (const flag of flags) {
        if (!flag) {
            return false;
        }
    }
    return true;
}
console.log(andMultipleExpr(true, true, false, false));

Некоторые люди могут бросить reduceэто, но решение Арчиevery намного лучше. (Но поскольку ваше сравнение не является строгим, я бы просто сделал это .every(flag => flag).)

Т.Дж. Crowder
источник
1
Спасибо. Это имеет больше смысла для меня :-)
Хаким Аса
В этом случае нет необходимости добавлять второй параметр в оператор Redu, получение первого параметра по умолчанию также будет работать.
Ник Зоум
1
@nickzoum - Только если мы можем предположить, что функция никогда не будет вызываться без аргументов, так как [].reduce((a,b)=>a && b)throws.
TJ Crowder
6

Ранний возврат должен сделать код более эффективным и более коротким:

function andMultipleExpr() {
  for (let i = 0; i < arguments.length; i++) {
    if (!arguments[i]) {
      return false;
    }
  }

  return true;
}
mbojko
источник
4

Я думаю, что это очень короткий путь с использованием ES6 Array.prototype.reduce

let andMultipleExpr = (...args) => args.reduce((a, b) => a && b);

console.log(andMultipleExpr(true, true, false, false));

Для получения более подробной информации о функции снижения, пожалуйста, прочитайте MDN

Патриссол Кенфак
источник
Если вы делаете , чтобы использовать метод массива, это гораздо лучше использовать , everyкак Арчи сделал чем reduce. Проще, и это короткие замыкания.
TJ Crowder
Это правда. Но давайте останемся сейчас, он хочет, но ЛОГИЧЕСКОЕ ИЛИ || теперь с уменьшением, это будет просто изменить && на ||
Патриссол Кенфак
Или everyк some. Все еще проще. Все еще короткие замыкания.
TJ Crowder
Отлично сработано. Ты прав @TJCrowder
Патриссол Кенфак
3

Вы можете взять Array#everyи вернуть последнее значение.

Такой подход возвращает реальный результат логического И&& .

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

function andMultipleExpr(...args) {
    var result; // any return value is configurable for empty args
    args.every(v => result = v);
    return result;
}

console.log(andMultipleExpr(true, true, false, false));
console.log(andMultipleExpr(true, true, 1, 2));
console.log(andMultipleExpr(true, 0, 1, 2));

Нина Шольц
источник
3

Возможно, вы хотите услышать, что пошло не так с циклом:

for (i = 0; i < arguments.length; i++){
  logicalAnd =  arguments[i] && arguments[i+1];
}
  1. этот цикл хранит &&последние два элемента, с которыми он сталкивается. В идеальном случае это были бы &&вместе два последних элемента массива (что уже не то, что вам нужно)
  2. Кроме того, в конце цикла i=arguments.length-1он проверяет последний элемент массива и i+1является элементом «после» последнего, то есть undefined. С точки зрения логических отношений это рассматривается false, но в этом случае &&создает само значение, и поэтому функция возвращает undefinedвсе время (это можно было упомянуть в вопросе).

Документы

expr1 && expr2: Если expr1можно преобразовать в true, возвращает expr2; еще, возвращается expr1.

arr=[true];
console.log("your case:",arr[0] && arr[1]);

console.log("1 && 2:", 1 && 2);


Вместо этого, вы должны использовать в logicalAndкачестве аккумулятора, который собирает результат &&-ную все предыдущие элементы, и хитрость , что вы можете использовать, если в результате частичного &&является false, это не имеет значения , что остальные элементы, конечный результат будет false, поэтому цикл может немедленно остановиться:

function andMultipleExpr(){
    let logicalAnd = arguments[0] || false;
    for (let i = 1; i < arguments.length && logicalAnd; i++){
        logicalAnd = logicalAnd && arguments[i];
    }
    return logicalAnd;
}

console.log("():",andMultipleExpr());
console.log("(false):",andMultipleExpr(false));
console.log("(true):",andMultipleExpr(true));
console.log("(true,true):",andMultipleExpr(true,true));
console.log("(true, true, false, false):",andMultipleExpr(true, true, false, false));

и затем вы можете оптимизировать его в соответствии с ответом Арчи : результат &&-ing элементов - это trueесли все элементы есть true, и вам не нужно выполнять одну &&операцию для вычисления результата:

function andMultipleExpr(){
    if(arguments.length===0){
      return false;
    }
    for (let i = 0; i < arguments.length; i++){
      if(!arguments[i]){
        return false;
      }
    }
    return true;
}

console.log("():",andMultipleExpr());
console.log("(false):",andMultipleExpr(false));
console.log("(true):",andMultipleExpr(true));
console.log("(true,true):",andMultipleExpr(true,true));
console.log("(true, true, false, false):",andMultipleExpr(true, true, false, false));

(В приведенных выше фрагментах я стремился falseсоздать пустой список аргументов.)

tevemadar
источник