Przypisać zmienną w warunku warunkowym, dobrą praktyką czy nie? [Zamknięte]


113

Rok temu przeniosłem się z klasycznych języków OO, takich jak Java, na JavaScript. Poniższy kod zdecydowanie nie jest zalecany (lub nawet nieprawidłowy) w Javie:

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;
}

Zasadniczo właśnie dowiedziałem się, że mogę przypisać zmienną do wartości w instrukcji warunku if i natychmiast sprawdzić przypisaną wartość tak, jakby była logiczna.

Dla większego bezpieczeństwa zwykle dzielę to na dwie linie kodu, najpierw przypisuję, a potem sprawdzam zmienną, ale teraz, kiedy to znalazłem, zastanawiam się tylko, czy jest to dobra praktyka w oczach doświadczonych programistów JavaScript?


"The following code is definitely not recommended (or event not correct) in Java..."Czy jest to poprawne w JavaScript? Ponieważ, o ile widzę, zwracasz liczbę całkowitą ( return parseInt(...)), jeśli dayNumber != -1jest prawdziwe, ale wartość logiczną, jeśli jest fałszywe.
Daniel Kvist,

Odpowiedzi:


117

Nie polecałbym tego. Problem polega na tym, że wygląda to na typowy błąd, podczas którego próbujesz porównać wartości, ale używasz pojedynczego =zamiast ==lub ===. Na przykład, gdy widzisz to:

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

nie wiesz, czy to właśnie mieli zamiar zrobić, czy też zamierzali napisać to:

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

Jeśli naprawdę chcesz wykonać zadanie na miejscu, polecam również wykonanie wyraźnego porównania:

if ((value = someFunction()) === <whatever truthy value you are expecting>) {
    ...
}

1
@Matthew Crumley: ta odpowiedź w jasny sposób odpowiada na moje pytanie. Nie sprawdzam, przypisując, ale sprawdzam, jaką wartość ma być po przypisaniu. Czy to zrozumienie jest właściwe?
Michael Mao,

1
@Michael: tak, zgadza się. Dodanie porównania po prostu sprawia, że ​​twoje intencje są bardziej jasne.
Matthew Crumley,

4
Ostatni przykład nie działa jednak, jeśli testujesz błąd / powodzenie funkcji, która zwraca wartość logiczną. Innymi słowy, chociaż if (resultArr = myNeedle.exec(myHaystack)) {...}działa, if ((resultArr = myNeedle.exec(myHaystack)) === true) {...}nie działa, ponieważ przypisanie do resultArr jest zawsze prawdziwe, nawet jeśli wynik funkcji nie jest. Jeśli ktoś używa this .. konstrukcji, pamiętaj, aby najpierw zadeklarować zmienną wynikową; „var” nie jest legalne w wyrażeniu warunku if.
Ville

3
Możesz używać if (!!(value = someFunction())), ale jak powiedziałeś, problem polega na tym, że nie możesz używać varwewnątrz, ifwięc albo tworzysz globalny, albo nic nie osiągasz, co i tak musisz zadeklarować valuew osobnym wierszu. Szkoda, bardzo podobała mi się ta konstrukcja w C ++.
riv

1
@riv, masz rację; w przypadku, gdy funkcja zwraca wartość logiczną - jak powiedziałem w moim powyższym komentarzu - wtedy warunek działa zgodnie z oczekiwaniami. Ale jeśli funkcja zwraca wartość logiczną (jak w moim przykładzie), to cała konstrukcja jest trochę pozbawiona sensu; najwyraźniej mój sposób myślenia był - sądząc po przykładzie - że funkcja zwróci tablicę. Szybki test wskazuje, że warunek ma wartość truetylko wtedy, gdy funkcja zwraca true, ale we wszystkich innych przypadkach (w tym gdy zwracana jest tablica, ciąg, liczba lub wartość null), ma wartość false.
Ville,

28

Nie widzę żadnego dowodu, że to nie jest dobra praktyka. Tak, może to wyglądać na błąd, ale można to łatwo naprawić poprzez rozsądne komentarze. Weź na przykład:

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

Dlaczego ta funkcja miałaby być uruchamiana po raz drugi z:

alert(processorIntensiveFunction());

Ponieważ pierwsza wersja WYGLĄDA źle? Nie mogę zgodzić się z tą logiką.


32
Nie odkopywanie starego komentarza, ale nie zgadzam się z twoimi argumentami. Czytelny kod powinien wyjaśniać się bez potrzeby komentarza - dodanie komentarza do mylącego kodu nie jest rozwiązaniem. Jeśli chodzi o drugą część, która mówi, że alternatywą jest ponowne wywołanie funkcji, nie sądzę, aby ktokolwiek miał zamiar to zrobić. Zamiast tego zrobiłbyśx = processorItensiveFunction(); if(x) { alert(x); }
maksim

9
@maksim: Lubię kod, który można czytać, ale to nie musi oznaczać, że kod powinien być przytłumiony lub zbyt szczegółowy. Rozprzestrzenianie rzeczy w wielu wierszach i żonglowanie wartościami między zmiennymi może w rzeczywistości prowadzić do gorszego kodu. Wstawiony kod może mieć nieprzewidziane skutki uboczne w słabo wpisanym / elastycznym języku, takim jak JS. Przypisanie w instrukcji warunkowej jest poprawne w javascript, ponieważ po prostu pytasz „jeśli przypisanie jest poprawne, zrób coś, co prawdopodobnie zawiera wynik przypisania”. Ale rzeczywiście, przypisywanie przed warunkiem jest również ważne, niezbyt szczegółowe i częściej używane.
okdewit

1
@maksim, dlaczego uważasz, że if ( ! x = anyFunction() )jest nieczytelny? Nie potrzebuje żadnych komentarzy.
JDrake

Jeśli naprawisz OPC, pracujesz z innymi programistami o różnym poziomie umiejętności (innymi słowy jesteś profesjonalistą), nienawidzisz, że jest to w ogóle możliwe.
davidjmcclelland

2
@maksim - również Twoje rozwiązanie byłoby bardzo niewygodne w danej if-elsesytuacji. Zastanów się - if (condition) {...} else if (x = processorIntensiveFunction()) {alert(x)} Twój przełożony x = processorIntensiveFunction();byłby zmarnowanym wysiłkiem, gdyby pierwotna treść conditionbyła prawdziwa.
Adrian Bartholomew

16

Robiłem to wiele razy. Aby ominąć ostrzeżenie JavaScript, dodaję dwa pareny:

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

Powinieneś tego unikać, jeśli naprawdę chcesz go używać, napisz nad nim komentarz, mówiąc o tym, co robisz.


1
@SHiNKiROU: jak mogę zobaczyć ostrzeżenia javascript? Czy istnieje kompilator Javascript? czy tłumacz wygeneruje jakieś ostrzeżenie? Używam konsoli Firefox tak jak w debugowaniu javascript przez cały czas, ale nigdy nie widzę podobnych wyników. Przepraszam za moje ograniczone doświadczenie.
Michael Mao,

5
@Michael: JSLint ( jslint.com ) to popularny program / biblioteka, która sprawdza programy JavaScript pod kątem możliwych błędów lub złego kodu.
Matthew Crumley,

Użyj przeglądarki Mozilla Firefox z rozszerzeniem Firebug i / lub Web Developer, aby sprawdzić ostrzeżenia.
Ming-Tang,

Po prostu wypróbowałem to z if ((a = [1, 2]).length > 0) { console.log(a); }gdzie anie jest jeszcze zainicjowane i rzeczywiście zadziałało (fajnie! Sprawia, że ​​użycie wyrażenia regularnego jest znacznie łatwiejsze). Czy to prawda, że ​​nie potrzebuję var|const|lettutaj żadnego ? Czy wiesz, gdzie mógłbym przeczytać więcej o tej sztuczce ?
t3chb0t

4

Możesz to zrobić również w Javie. I nie, to nie jest dobra praktyka. :)

(I użyj ===w Javascript do wpisania równości. Przeczytaj książkę Crockforda The Good Parts o JS.)


@quixoto: Czy mogę zrobić tę sztuczkę w Javie? Zastanawiam się ... Nie mam jdk w ręcznym bankomacie, więc nie mogę pobrać przykładowego kodu w Javie. Z mojej słabej pamięci Java po prostu wyświetli błąd Runtime, jeśli zwracana wartość ocenia coś nie logicznego, jak w przypadku instrukcji warunkowej, prawda?
Michael Mao,

1
Ach, tak, w Javie sprawdzany jest typ, aby był typem logicznym. Ale możesz to zrobićif (foo = getSomeBoolValue()) { }
Ben Zotto,

tak to prawda. zmienna logiczna do testowania, czy coś się powiodło i inna zmienna do przechowywania zwracanej wartości. Tak właśnie działa Java, zbyt dobrze ją znam, więc czuję się dziwnie, widząc, że Javascript może zrobić dwie rzeczy w jednej linii :)
Michael Mao

@BenZotto to nie jest dobra praktyka, dlaczego? „Aby uniknąć przypadkowego niewłaściwego użycia zmiennej, zwykle dobrym pomysłem jest wprowadzenie zmiennej w możliwie jak najmniejszym zakresie. W szczególności zazwyczaj najlepiej jest opóźnić definicję zmiennej, aż można nadać jej wartość początkową ... Jednym z najbardziej eleganckich zastosowań tych dwóch zasad jest zadeklarowanie zmiennej jako warunku. " - Stroustrup, „Język programowania C ++”.
JDrake,

1
Cześć, przyszedłem tutaj jako użytkownik javascript node.js. Dlaczego nie jest to dobra praktyka w jednym przypadku, z którym boli mnie: if (myvar = 'tylko test') Tworzy zmienną GLOBAL node.js myvar ( nodejs.org/docs/latest-v12.x/api/globals.html #globals_global ). Więc jeśli jesteś podobny do mnie i używałeś tej zmiennej w obsłudze żądań serwera (wracając do niej po kilku sekundach, gdy inne żądania mogły spaść i takie tam), możesz być zaskoczony uzyskanymi wynikami. Dlatego zalecenie jest następujące: pamiętaj, że ten wzorzec tworzy zmienną globalną w node.js.
pein-consulting.de

4

Jest jeden przypadek, kiedy to robisz, z while-loops.
Czytając pliki, zwykle robisz to:

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
        }
    }
}

Spójrz na while-loop w linii 9. Tam, nowa linia jest odczytywana i zapisywana w zmiennej, a następnie uruchamiana jest zawartość pętli. Wiem, że to nie jest stwierdzenie- if, ale myślę, że w twoim pytaniu można również zawrzeć pętlę while.

Powodem tego jest to, że gdy używasz a FileInputStream, za każdym razem, gdy wywołujesz FileInputStream.readLine(), odczytuje on następną linię w pliku, więc gdybyś wywołał go z pętli fileIn.readLine() != nullbez przypisywania zmiennej, zamiast wywoływać (currentLine = fileIn.readLine()) != null, a następnie wywołać go z wewnątrz pętli, dostaniesz tylko co drugą linię.

Mam nadzieję, że rozumiesz i powodzenia!


3

Możesz również wykonywać przypisania w instrukcjach if w języku Java. Dobrym przykładem może być przeczytanie i wypisanie czegoś:

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

Kod:

// 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: dzięki za ten przykład. Jestem naprawdę nie pro albo Java lub JavaScript ... Dobrze jest wiedzieć, to podejście jest również możliwe w Javie :)
Michael Mao

Nie widzę w tym sensu. Możesz to zrobić w Javie, PHP i wielu innych językach. Pytanie dotyczyło Javascript.
pmrotule

Nie, niekoniecznie, musisz uważnie przeczytać ponownie pytanie.
Nitrodist

3

Gdybyś miał odnieść się do książki Martina Fowlersa Refaktoryzacja ulepszająca projekt istniejącego kodu ! Następnie jest kilka przypadków, w których byłaby to dobra praktyka, np. długie, złożone warunki warunkowe do użycia funkcji lub wywołania metody w celu potwierdzenia sprawy:

"Motywacja

Jednym z najpowszechniejszych obszarów złożoności programu jest złożona logika warunkowa. Pisząc kod do testowania warunków i robienia różnych rzeczy w zależności od różnych warunków, szybko otrzymujesz dość długą metodę. Długość metody jest sama w sobie czynnikiem utrudniającym jej odczytanie, ale warunki zwiększają trudność. Problem zwykle polega na tym, że kod, zarówno w sprawdzaniu warunków, jak iw działaniach, mówi ci, co się dzieje, ale może łatwo zaciemnić, dlaczego tak się dzieje.

Podobnie jak w przypadku każdego dużego bloku kodu, możesz wyjaśnić swój zamiar, rozkładając go i zastępując fragmenty kodu wywołaniem metody nazwanym tak, jak intencja tego bloku kodu. > W przypadku warunków możesz uzyskać dalsze korzyści, robiąc to w przypadku części warunkowej i każdej z alternatyw. W ten sposób podkreślisz warunek i jasno określisz, na czym się> rozgałęziasz. Podkreślasz również przyczynę rozgałęzienia ”.

I tak, jego odpowiedź dotyczy również implementacji języka Java. W przykładach nie przypisuje funkcji warunkowej do zmiennej.


1

To nie jest dobra praktyka. Wkrótce się z tym pogubisz. Wygląda podobnie do typowego błędu: niewłaściwego użycia operatorów „=” i „==”.

Powinieneś podzielić go na 2 wiersze kodów. Pomaga to nie tylko uczynić kod bardziej przejrzystym, ale także ułatwia jego refaktoryzację w przyszłości. Wyobraź sobie, że zmieniasz warunek IF? Możesz przypadkowo usunąć wiersz, a zmienna nie będzie już mieć przypisanej do niej wartości.


@thethanghn: właśnie tego się boję. kiedy podrosną i leniwy po prostu nie chcą, aby wpisać więcej do kodu jeśli mniej klawiszy po prostu wystarczą :)
Michael Mao

1
Nie, nie gubię się i robię to cały czas. Są z tego korzyści.
JDrake,

Ale to naprawdę zależy, prawda? Jeśli pochodzisz ze środowiska „C” (i innych języków opartych na C), to konstrukcja jest bardzo znajoma, a alternatywy są bardzo niezręczne. IMO, jest to coś, czego można się nauczyć, a potem już wiesz. To nie jest coś, o co możesz się potknąć więcej niż raz.
Max Waterman

0

Uznałbym to za bardziej oldschoolowy styl C; nie jest to dobra praktyka w JavaScript, więc powinieneś jej unikać.


8
Nie uważam tego również za dobrą praktykę w języku C.
Matthew Crumley,

1
Uważam to za dobrą praktykę w wielu językach.
JDrake,

Samo powiedzenie „niedobra praktyka” nie wystarczy, imo. Tak naprawdę chodzi tylko o edukację - nauczyliśmy się tego raz i to wszystko.
Max Waterman


0

Przyjechałem tu z Golang, gdzie często można zobaczyć coś takiego

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

W którym errjest ograniczony tylko do tego ifbloku. W związku z tym oto, co robię w es6, co wydaje się dość brzydkie, ale nie sprawia, że ​​moje raczej surowe zasady eslinta jęczą i osiągają to samo.

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

Dodatkowe nawiasy klamrowe definiują nowy, hm, „zakres leksykalny”? Co oznacza, że ​​mogę używać consti errnie jest dostępny dla zewnętrznego bloku.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.