Назначить переменную в условном выражении if, хорошая практика или нет? [закрыто]

113

Год назад я перешел с классических объектно-ориентированных языков, таких как Java, на JavaScript. Следующий код определенно не рекомендуется (или даже неправильно) в Java:

if(dayNumber = getClickedDayNumber(dayInfo))
{
    alert("day number found : " + dayNumber);
}
function getClickedDayNumber(dayInfo)
{
    dayNumber = dayInfo.indexOf("fc-day");
    if(dayNumber != -1) //substring found
    {
        //normally any calendar month consists of "40" days, so this will definitely pick up its day number.
        return parseInt(dayInfo.substring(dayNumber+6, dayNumber+8));
    }
    else return false;
}

По сути, я только что обнаружил, что могу присвоить переменной значение в операторе условия if и немедленно проверить присвоенное значение, как если бы оно было логическим.

Для большей безопасности я обычно разделяю это на две строки кода, сначала назначаю, а затем проверяю переменную, но теперь, когда я это нашел, мне просто интересно, является ли это хорошей практикой или нет в глазах опытных разработчиков JavaScript?

Майкл Мао
источник
"The following code is definitely not recommended (or event not correct) in Java..."Это вообще правильно в JavaScript? Потому что, насколько я понимаю, вы возвращаете целое число ( return parseInt(...)), если dayNumber != -1оно истинно, и логическое значение, если оно ложно.
Даниэль Квист

Ответы:

117

Я бы не рекомендовал это. Проблема в том, что это похоже на обычную ошибку, когда вы пытаетесь сравнить значения, но используете одно =вместо ==или ===. Например, когда вы видите это:

if (value = someFunction()) {
    ...
}

вы не знаете, хотели ли они это сделать, или они намеревались написать это:

if (value == someFunction()) {
    ...
}

Если вы действительно хотите выполнить задание на месте, я бы также рекомендовал провести явное сравнение:

if ((value = someFunction()) === <whatever truthy value you are expecting>) {
    ...
}
Мэтью Крамли
источник
1
@ Мэтью Крамли: это ясно отвечает на мой вопрос. Я не проверяю путем присвоения, а проверяю то, что значение оценивается после присвоения. Правильно ли это понимание?
Майкл Мао
1
@ Майкл: да, это правильно. Добавление сравнения просто проясняет ваши намерения.
Мэтью Крамли
4
Однако последний пример не работает, если вы проверяете сбой / успех функции, возвращающей логическое значение. Другими словами, while if (resultArr = myNeedle.exec(myHaystack)) {...}работает, if ((resultArr = myNeedle.exec(myHaystack)) === true) {...}но не работает, потому что присвоение resultArr всегда истинно, даже если результат функции - нет. Если кто-нибудь использует эту конструкцию .., не забудьте сначала объявить переменную результата; Использование 'var' в операторе условия if недопустимо.
Вилле
3
Вы можете использовать if (!!(value = someFunction())), но, как вы сказали, проблема в том, что вы не можете использовать varвнутри, ifпоэтому вы либо создаете глобал, либо ничего не добиваетесь, поскольку вы valueвсе равно должны объявить в отдельной строке. Жаль, мне очень понравилась эта конструкция на C ++.
riv
1
@riv, ты прав; в случае, если функция возвращает логическое значение - как я сказал в своем комментарии выше - тогда условное выражение работает должным образом. Но если функция возвращает логическое значение (как в моем примере), тогда вся конструкция не имеет смысла; ясно, что я думал, судя по примеру, что функция вернет массив. Быстрый тест показывает, что условие оценивается trueтолько тогда, когда функция возвращается true, но во всех других случаях (включая возвращение массива, строки, числа или нуля) оно оценивается false.
Вилле
28

Я не вижу доказательств того, что это плохая практика. Да, это может показаться ошибкой, но это легко исправить, если прокомментировать. Взять, к примеру:

if (x = processorIntensiveFunction()) { // declaration inside if intended
    alert(x);
}

Почему этой функции должно быть разрешено запускаться второй раз с:

alert(processorIntensiveFunction());

Потому что первая версия ВЫГЛЯДИТ плохо? Я не могу согласиться с такой логикой.

Адриан Варфоломей
источник
32
Не копать старый комментарий, но я не согласен с вашими аргументами. Читаемый код должен объяснять себя без необходимости в комментариях - добавление комментария к сбивающему с толку коду не является лекарством. Что касается второй части, в которой говорится, что альтернативой является повторный вызов функции, я не думаю, что кто-то собирается это делать. Вместо этого вы бы сделалиx = processorItensiveFunction(); if(x) { alert(x); }
максим
9
@maksim: мне нравится читаемый код, но это не обязательно означает, что код должен быть упрощенным или слишком подробным. Распространение вещей на несколько строк и жонглирование значениями между переменными на самом деле может привести к ухудшению кода. Вставленный код может иметь непредвиденные побочные эффекты на слабо типизированном / гибком языке, таком как JS. Присвоение в условном выражении допустимо в javascript, потому что вы просто спрашиваете: «Если присвоение допустимо, сделайте что-нибудь, что, возможно, включает результат присвоения». Но действительно, присвоение перед условным условием также допустимо, не слишком многословно и используется чаще.
okdewit
1
@maksim, почему вы думаете, что if ( ! x = anyFunction() )это не читается? Это вообще не нуждается в комментариях.
JDrake
Если вы исправите OPC, поработаете с другими разработчиками с разным уровнем навыков (другими словами, вы профессионал), вы возненавидите, что это вообще возможно.
davidjmcclelland
2
@maksim - и ваше решение было бы очень неудобным в if-elseситуации. Подумайте: если бы исходная информация была верной, if (condition) {...} else if (x = processorIntensiveFunction()) {alert(x)} ваши предыдущие x = processorIntensiveFunction();усилия были бы напрасными condition.
Адриан Бартоломью
16

Я делал это много раз. Чтобы обойти предупреждение JavaScript, я добавляю две скобки:

if ((result = get_something())) { }

Вам следует избегать этого, если вы действительно хотите его использовать, напишите над ним комментарий, рассказывающий, что вы делаете.

Мин-Тан
источник
1
@SHiNKiROU: как я могу увидеть предупреждения javascript? Есть ли компилятор Javascript? или интерпретатор выдаст какое-то предупреждение? Я все время использую консоль Firefox, как и при отладке javascript, но никогда не вижу подобных результатов. Извините за мой ограниченный опыт.
Майкл Мао
5
@Michael: JSLint ( jslint.com ) - популярная программа / библиотека, которая проверяет программы JavaScript на возможные ошибки или плохой код.
Мэтью Крамли
Используйте Mozilla Firefox с расширением Firebug и / или Web Developer для проверки предупреждений.
Ming-Tang
Я просто попробовал, if ((a = [1, 2]).length > 0) { console.log(a); }где aеще нигде не инициализирован, и это действительно сработало (приятно! Значительно упрощает использование регулярного выражения). Верно ли, что мне здесь ничего не нужно var|const|let? Вы случайно не знаете, где я могу подробнее прочитать об этом трюке ?
t3chb0t
4

Вы можете сделать это и на Java. И нет, это плохая практика. :)

(И используйте ===в Javascript для типизированного равенства. Прочтите книгу Крокфорда «Хорошие части» по JS.)

Бен Зотто
источник
@quixoto: Могу ли я проделать этот трюк на Java? Интересно ... У меня нет jdk под рукой, поэтому я не могу получить образец кода на Java. Из-за моей плохой памяти Java просто выдаст вам ошибку времени выполнения, если возвращаемое значение оценивает что-то не логическое, как в условном выражении if, верно?
Майкл Мао
1
Ах, да, в Java он проверяется как логический тип. Но вы можете это сделатьif (foo = getSomeBoolValue()) { }
Бен Зотто
Да, это верно. логическая переменная для проверки успешности чего-либо и другая переменная для хранения возвращенного значения. Вот как Java выполняет свою работу, я слишком хорошо знаком с этим, поэтому мне странно видеть, что Javascript может делать две вещи в одной простой строке :)
Майкл Мао,
@BenZotto, почему это не лучшая практика? «Чтобы избежать случайного неправильного использования переменной, обычно рекомендуется ввести переменную в минимально возможную область видимости. В частности, обычно лучше отложить определение переменной до тех пор, пока ей не будет присвоено начальное значение ... Одно из самых элегантных применений этих двух принципов - объявление переменной в условном выражении ". - Страуструп, «Язык программирования C ++».
JDrake 08
1
Привет, я пришел сюда как пользователь javascript node.js. Почему это не очень хорошая практика в одном случае, с которым у меня возникла боль: if (myvar = 'just a test') Создает ГЛОБАЛЬНУЮ переменную node.js myvar ( nodejs.org/docs/latest-v12.x/api/globals.html #globals_global ). Так что, если вы похожи на меня и использовали эту переменную при обработке запросов к серверу (возвращаясь к ней через несколько секунд, когда могли появиться другие запросы и т. Д.), Вы можете быть удивлены тем, какие результаты вы получите. Итак, рекомендация: имейте в виду, что этот шаблон создает глобальную переменную в node.js.
pein-consulting.de
4

Есть один случай, когда вы это делаете с while-loops.
При чтении файлов вы обычно делаете так:

void readFile(String pathToFile) {
    // Create a FileInputStream object
    FileInputStream fileIn = null;
    try {
        // Create the FileInputStream
        fileIn = new FileInputStream(pathToFile);
        // Create a variable to store the current line's text in
        String currentLine;
        // While the file has lines left, read the next line,
        // store it in the variable and do whatever is in the loop
        while((currentLine = in.readLine()) != null) {
            // Print out the current line in the console
            // (you can do whatever you want with the line. this is just an example)
            System.out.println(currentLine);
        }
    } catch(IOException e) {
        // Handle exception
    } finally {
        try {
            // Close the FileInputStream
            fileIn.close();
        } catch(IOException e) {
            // Handle exception
        }
    }
}

Посмотрите на while-loop в строке 9. Здесь новая строка считывается и сохраняется в переменной, а затем выполняется содержимое цикла. Я знаю, что это не ifзаявление, но я думаю, что в ваш вопрос также можно включить цикл while.

Причина этого в том, что при использовании a FileInputStreamкаждый раз, когда вы вызываете FileInputStream.readLine(), он читает следующую строку в файле, поэтому, если бы вы вызывали его из цикла, просто fileIn.readLine() != nullне назначая переменную, вместо вызова (currentLine = fileIn.readLine()) != null, а затем вызывали ее из внутри цикла вы получите только каждую вторую строку.

Надеюсь, вы понимаете, и удачи!

Даниэль Квист
источник
3

Вы также можете выполнять присваивания внутри операторов if в Java. Хорошим примером будет чтение и запись чего-либо:

http://www.exampledepot.com/egs/java.io/CopyFile.html?l=new

Код:

// Copies src file to dst file.
// If the dst file does not exist, it is created
void copy(File src, File dst) throws IOException 
{
    InputStream in = new FileInputStream(src);
    OutputStream out = new FileOutputStream(dst);

    // Transfer bytes from in to out
    byte[] buf = new byte[1024];
    int len;
    while ((len = in.read(buf)) > 0) {
        out.write(buf, 0, len);
    }
    in.close();
    out.close();
}
Nitrodist
источник
@Nitrodist: спасибо за этот пример. Я действительно не профессионал ни в Java, ни в javascript ... Приятно знать, что этот подход возможен и в Java :)
Майкл Мао
Я не вижу в этом смысла. Вы можете сделать это на Java, PHP и многих других языках. Вопрос был про Javascript.
pmrotule
Нет, это не обязательно, вам нужно внимательно перечитать вопрос.
Nitrodist 01
3

Если вы обратитесь к книге Мартина Фаулера « Рефакторинг», улучшающей дизайн существующего кода ! Тогда есть несколько случаев, когда это было бы хорошей практикой, например. длинные сложные условные выражения для использования вызова функции или метода для подтверждения вашего случая:

«Мотивация

Одна из наиболее распространенных областей сложности в программе - сложная условная логика. Когда вы пишете код для тестирования условий и для выполнения различных действий в зависимости от различных условий, вы быстро получаете довольно длинный метод. Длина метода сама по себе является фактором, затрудняющим чтение, но условия увеличивают сложность. Проблема обычно заключается в том, что код, как в проверках условий, так и в действиях, сообщает вам, что происходит, но может легко скрыть, почему это происходит.

Как и в случае с любым большим блоком кода, вы можете прояснить свое намерение, разложив его и заменив фрагменты кода вызовом метода, названным в честь намерения этого блока кода. > С условиями вы можете получить дополнительную выгоду, сделав это для условной части и каждой из альтернатив. Таким образом, вы выделите условие и четко сделаете, к чему вы переходите. Вы также указываете причину ветвления ".

И да, его ответ также действителен для реализаций Java. В примерах он не назначает условную функцию переменной.

Аллан
источник
1

Это не лучшая практика. Вы скоро запутаетесь в этом. Это похоже на обычную ошибку: неправильное использование операторов "=" и "==".

Вы должны разбить его на 2 строки кода. Это не только помогает сделать код более понятным, но и упрощает рефакторинг в будущем. Представьте, что вы меняете условие ЕСЛИ? Вы можете случайно удалить строку, и ваша переменная больше не получит присвоенное ей значение.

Thethanghn
источник
@thethanghn: именно этого я и боюсь. когда я становлюсь старше и ленив, я просто не хочу вводить больше в код, если будет достаточно меньшего количества нажатий клавиш :)
Майкл Мао,
1
Нет, я не запутываюсь и делаю это постоянно. В этом есть свои преимущества.
JDrake 08
Однако это действительно зависит от обстоятельств, не так ли? Если вы пришли из фона C (и других языков, основанных на C), то конструкция вам очень знакома, а альтернативы очень неудобны. ИМО, это то, чему научились один раз, и тогда вы узнаете. Это не то, о чем вы споткнетесь более одного раза.
Макс Уотерман,
0

Я бы счел это больше стилем C старой школы; это не очень хорошая практика в JavaScript, поэтому вам следует избегать этого.

Джастин Этье
источник
8
Я тоже не считаю это хорошей практикой в ​​Си.
Мэтью Крамли
1
Я считаю это хорошей практикой во многих языках.
JDrake 08
Просто сказать «плохая практика» недостаточно, имо. На самом деле речь идет только об образовании - его узнают один раз, и все.
Макс Уотерман,
0

вы можете сделать что-то вроде этого:

if (value = /* sic */ some_function()){
  use_value(value)
}
Джозеф Ле Бреч
источник
0

Я приехал сюда из Голанга, где часто можно увидеть что-то вроде

if (err := doSomething(); err != nil) {
    return nil, err
}

В которой errраспространяется до этого ifтолько блок. Таким образом, вот то, что я делаю в es6, что кажется довольно уродливым, но не делает мои довольно строгие правила eslint жалкими и добивается того же.

{
  const err = doSomething()
  if (err != null) {
    return (null, err)
  }
}

Дополнительные фигурные скобки определяют новую "лексическую область видимости"? Это означает, что я могу использовать constи errнедоступен для внешнего блока.

Адам Барнс
источник