Призначити змінну, якщо заява про стан, хороша практика чи ні? [зачинено]


113

Я перейшов рік тому з класичних мов OO, таких як 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
@Matthew Crumley: це чітко відповідає на моє запитання. Я не перевіряю, присвоюючи, але перевіряючи значення, яке оцінюється після призначення. Чи правильно це розуміння?
Майкл Мао

1
@Michael: так, це правильно. Додавання порівняння в основному просто робить ваші наміри більш зрозумілими.
Меттью Крамлі

4
Останній приклад не працює, якщо ви перевіряєте на помилку / успіх функції, яка повертає булеву форму. Іншими словами, хоча це 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, щоб перевірити попередження.
Мінг-Тан

Я просто спробував це if ((a = [1, 2]).length > 0) { console.log(a); } там a, де ще ніде не ініціалізовано, і він справді спрацював (приємно! Робить використання регексу набагато простіше). Це правильно, що мені тут нічого не потрібно var|const|let? Чи знаєте ви, де я міг би прочитати більше про цю хитрість ?
t3chb0t

4

Це можна зробити і на Java. І ні, це не є хорошою практикою. :)

(І використовуйте ===в Javascript для введеної рівності. Читайте книгу Крокфорда "Гарні частини" на JS.)


@quixoto: Чи можу я зробити цю хитрість на Java? Цікаво ... У мене немає jdk від руки atm, тому я не можу отримати зразок коду на Java. З моєї поганої пам’яті Java просто отримає помилку виконання, якщо значення, що повертається, оцінює щось не булеве, як у умовному заяві, правда?
Майкл Мао

1
Ага, так, у Java це перевірено на тип булевого типу. Але ви можете зробитиif (foo = getSomeBoolValue()) { }
Бен Zotto

так, це правильно. булева змінна, щоб перевірити, чи вдалося щось вдалося, а інша змінна для збереження повернутого значення. Ось як Java виконує свою роботу, я занадто добре знайомий з цим, тому мені дивно бачити, що Javascript може робити дві речі за один простий рядок :)
Майкл Мао

@BenZotto це не дуже добра практика, чому? "Щоб уникнути випадкового неправомірного використання змінної, зазвичай є хорошою ідеєю ввести змінну в найменший можливий діапазон. Зокрема, зазвичай найкраще затримати визначення змінної, поки не зможете надати їй початкове значення ... Одне з найелегантніших застосувань цих двох принципів - оголосити змінну умовною ». - Stroustrup, "Мова програмування C ++".
JDrake

1
Привіт, я прийшов сюди як користувач JavaScript node.js. Чому в одній справі це не є хорошою практикою, у мене виникли болі з: якщо (myvar = 'просто тест') створює змінну nvar.js GLOBAL 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 твердження, але певний час цикл може бути також включений у ваше запитання.

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

Сподіваюся, ви зрозуміли, і удачі!


3

Ви також можете виконувати завдання, якщо викладати і 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: дякую за цей приклад. Мені справді не до душі ні Java, ні JavaScript ... Добре знати, що такий підхід також можливий на Java :)
Майкл Мао

Я не бачу сенсу в цьому. Це можна зробити на Java, PHP та багатьох інших мовах. Питання стосувалося Javascript.
pmrotule

Ні, це не обов'язково, потрібно уважно перечитати питання.
Нітродіст

3

Якби ви зверталися до книги Мартіна Фаулерса Refactoring, що покращує дизайн існуючого коду ! Тоді є кілька випадків, коли це було б хорошою практикою, наприклад. довгі складні умови для використання виклику функції або методу для затвердження вашого випадку:

"Мотивація

Одна з найпоширеніших областей складності програми полягає у складній умовної логіці. Коли ви пишете код для тестування умов і робити різні речі залежно від різних умов, ви швидко закінчитесь досить довгим методом. Тривалість методу сама по собі є фактором, який ускладнює читання, але умови збільшують труднощі. Проблема, як правило, полягає в тому, що код, як у перевірках стану, так і в дії, говорить вам про те, що відбувається, але може легко затьмарити, чому це відбувається.

Як і у будь-якому великому блоці коду, ви можете зробити свій намір зрозумілішим, розклавши його та замінивши шматки коду викликом методу, названим за наміром цього блоку коду. > За умови ви можете отримати додаткову вигоду, зробивши це для умовної частини та кожної з альтернатив. Таким чином ви виділяєте умову і чітко даєте зрозуміти, на що ви> розгалужуєте. Ви також підкреслюєте причину розгалуження ".

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


1

Це не найкраща практика. Ви незабаром збентежитеся. Це схоже на загальну помилку: неправильне використання операторів "=" та "==".

Ви повинні розбити його на 2 рядки кодів. Це не тільки допомагає зробити код більш зрозумілим, але й легко переробляти в майбутньому. Уявіть, що ви змінюєте стан IF? Ви можете випадково видалити рядок, і ваша змінна більше не отримає призначене їй значення.


@thethanghn: саме цього я боюся. коли я дорослішаю і лінуюся, я просто не хочу більше вводити код, якщо буде достатньо менше натискань клавіш :)
Майкл Мао

1
Ні, я не плутаюсь і постійно роблю це. У цьому є переваги.
JDrake

Це насправді залежить, чи не так? Якщо ви походите з "C" фону (та інших мов, заснованих на C), то конструкція дуже знайома, а альтернативи дуже незручні. ІМО, це щось, що вивчається один раз, а потім ви знаєте. Це не те, що ви будете подорожувати не раз.
Макс Вотерман

0

Я вважав би це більш старожитним стилем С; Це не дуже хороша практика роботи в JavaScript, тому вам слід уникати цього.


8
Я також не вважаю це доброю практикою в С.
Меттью Крамлі

1
Я вважаю це гарною практикою на багатьох мовах.
JDrake

Просто сказати, що "недостатня практика" недостатньо, іммо. Це справді лише про освіту - вона засвоюється один раз, і все.
Макс Вотерман


0

Я приїхав сюди з Голангу, де звичайно бачити щось подібне

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

У якому errрозміщено лише цей ifблок. Отож, ось що я роблю в es6, що здається досить некрасивим, але не робить моїх досить суворих правил дефіле, і домагається того ж.

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

Додаткові дужки визначають новий, е-е, "лексичний обсяг"? Що означає, що я можу використовувати const, і errнедоступний для зовнішнього блоку.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.