if条件ステートメントで変数を割り当てますか、良い習慣かどうか?[閉まっている]


113

私は1年前に、Javaなどの古典的なOO言語から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条件ステートメントの値に変数を割り当てて、割り当てられた値をブール値であるかのようにすぐにチェックできることがわかりました。

より安全な賭けのために、私は通常それを2行のコードに分けて、最初に割り当ててから変数をチェックしますが、これを見つけたので、経験豊富なJavaScript開発者の目には良い習慣かどうか疑問に思っていますか?


"The following code is definitely not recommended (or event not correct) in Java..."JavaScriptでも正しいですか?なぜなら、私が見る限り、trueのreturn parseInt(...)場合dayNumber != -1は整数()を返し、falseの場合はブール値を返すためです。
Daniel Kvist 2015

回答:


117

私はそれをお勧めしません。問題は、値を比較しようとする一般的なエラーのように見えますが===またはの代わりに単一を使用することです===。たとえば、次のような場合:

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

それが彼らがやろうとしていたことなのか、あるいは彼らがこれを書くつもりだったのかはわかりません。

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

割り当てを適切に行う必要がある場合は、明示的な比較も行うことをお勧めします。

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

1
@Matthew Crumley:これは私の質問に明確に答えます。私は割り当てによってチェックするのではなく、割り当て後に評価される値をチェックします。この理解は正しいですか?
Michael Mao

1
@マイケル:はい、そうです。比較を追加すると、基本的に意図がより明確になります。
Matthew Crumley、2010

4
ただし、ブール値を返す関数の失敗/成功をテストしている場合、最後の例は機能しません。言い換えれば、一方で if (resultArr = myNeedle.exec(myHaystack)) {...}作品、if ((resultArr = myNeedle.exec(myHaystack)) === true) {...}関数の結果がない場合でもresultArrへの割り当ては常にtruthyされていないため。誰かがこれを使用する場合は、..構文を使用する場合は、必ず最初に結果変数を宣言してください。'var'はif条件ステートメント内では無効です。
Ville、

3
を使用できますがif (!!(value = someFunction()))、言ったように、問題はvar内部で使用できないためif、グローバルを作成するか、valueとにかく別の行で宣言する必要があるため、何も実行しないことです。恥、私はこの構造をC ++で本当に気に入りました。
riv 2015年

1
@riv、あなたは正しい。上記のコメントで述べたように、関数がブール値を返す場合、条件は期待どおりに機能します。しかし、関数が(私の例のように)ブール値を返す場合、構造全体は一種の意味がありません。明らかに、私の例は、この例から判断すると、関数は配列を返すというものでした。簡単なテストはtrue、関数がを返した場合にのみ条件が評価されることを示していますtrueが、それ以外の場合(配列、文字列、数値、またはnullが返された場合を含む)では、条件はに評価されfalseます。
Ville

27

それが良い習慣ではないという証拠はありません。はい、それは間違いのように見えるかもしれませんが、それは賢明なコメントによって簡単に修正されます。例えば:

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

なぜその関数が2回目の実行を許可されるのか:

alert(processorIntensiveFunction());

最初のバージョンが悪いので?その論理には同意できません。


32
古いコメントを掘り下げることはしませんが、私はあなたの主張に同意しません。読みやすいコードは、コメントを必要とせずにそれ自体を説明する必要があります-混乱するコードにコメントを追加することは救済策ではありません。もう1つの方法として、関数をもう一度呼び出すという方法がありますが、これを行うつもりはないと思います。代わりにあなたはそうするでしょうx = processorItensiveFunction(); if(x) { alert(x); }
maksim '25 / 12/25

8
@maksim:私は可読コードが好きですが、それは必ずしもコードが簡潔であるか、または冗長すぎる必要があることを意味しません。複数の行に分散し、変数間で値をジャグリングすると、実際にはコードの品質が低下する可能性があります。挿入されたコードは、JSのような弱く型付けされた/柔軟な言語で予期しない副作用を引き起こす可能性があります。条件付きステートメントでの割り当てはJavaScriptで有効です。なぜなら、「割り当てが有効な場合、割り当ての結果を含む可能性のあることを実行する」ためです。しかし、実際には、条件の前に割り当てることも有効であり、冗長すぎず、より一般的に使用されています。
okdewit 2015

1
@maksimなぜif ( ! x = anyFunction() )読めないと思いますか?コメントは一切必要ありません。
JDrake 2017年

OPCを修正し、さまざまなスキルレベルの他の開発者と協力する場合(つまり、あなたはプロです)、これが可能であることさえ嫌いです。
davidjmcclelland 2017年

2
@maksim-また、if-else状況によってはソリューションが非常に不便になります。検討- if (condition) {...} else if (x = processorIntensiveFunction()) {alert(x)} あなたの以前のx = processorIntensiveFunction();ことは、イニシャルconditionが真実である場合、無駄な努力になるでしょう。
エイドリアンバーソロミュー

16

何度もやった。JavaScriptの警告をバイパスするには、2つの括弧を追加します。

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

使用を避けたい場合は、その上にコメントを書き込んでください。


1
@SHiNKiROU:JavaScriptの警告を表示するにはどうすればよいですか?JavaScriptコンパイラはありますか?それとも通訳が何らかの警告を発するのでしょうか?私は常にJavaScriptデバッグのようにFirefoxコンソールを使用していますが、同様の出力が表示されません。私の限られた経験について申し訳ありません。
Michael Mao

5
@Michael:JSLint(jslint.com)は、JavaScriptプログラムに間違いや不良コードがないかチェックする人気のプログラム/ライブラリです。
Matthew Crumley、2010

FirebugまたはWeb Developer拡張機能、あるいはその両方でMozilla Firefoxを使用して警告を確認します。
Ming-Tang

まだどこも初期化されていない場所if ((a = [1, 2]).length > 0) { console.log(a); }で試してみましたが、a実際に機能しました(素晴らしい!正規表現の使用がはるかに簡単になります)。これは私がvar|const|letここで必要としないものですか?私はこのトリックについてどこでもっと読むことができるか知っていますか?
t3chb0t

4

Javaでもこれを行うことができます。いいえ、それは良い習慣ではありません。:)

(そして===、型付きの等価性のためにJavaScriptでinを使用します。JSに関するCrockfordのThe Good Partsの本を読んでください。)


@quixoto:このトリックをJavaで実行できますか?どうやら...私は手動のATMでjdkを持っていないので、Javaでサンプルコードを取得できません。私の貧弱なメモリから、戻り値がif条件ステートメントのようにブール値ではないものを評価する場合、Javaはランタイムエラーを取得するだけですよね?
Michael Mao

1
ああ、そうです、Javaでは、ブール型であることが型チェックされます。しかし、あなたはできませんif (foo = getSomeBoolValue()) { }
ベンZotto

はい、そのとおり。何かが成功したかどうかをテストするブール変数と、返された値を格納する別の変数。これがJavaの機能です。私はそれに慣れすぎているので、Javascriptが1行で2つのことを実行できるのを見るのは奇妙に感じます:)
Michael Mao

@BenZottoそれはなぜ良い習慣ではないのですか?「変数の偶発的な誤用を避けるために、通常、変数を可能な限り最小のスコープに導入することをお勧めします。特に、初期値を指定できるようになるまで変数の定義を遅らせることが通常最善です...これら2つの原則の最も洗練された用途の1つは、条件付きで変数を宣言することです。」-Stroustrup、「C ++プログラミング言語」。
JDrake 2017年

1
こんにちは、node.js javascriptユーザーとしてここに来ました。なぜ私が苦労したあるケースで良い習慣がないのですか:if(myvar = 'just a test')create a node.js GLOBAL variable myvar(nodejs.org/docs/latest-v12.x/​​api/globals.html #globals_global)。したがって、私と同じように、サーバーの要求処理でこの変数を使用した場合(他の要求が落ち込んだ可能性がある場合に数秒後に戻ってくる)、結果に驚くでしょう。したがって、推奨事項は次のとおりです。このパターンは、node.jsにグローバル変数を作成することに注意してください。
pein-consulting.de

4

while-loopsを使用する場合、1つのケースがあります。
ファイルを読み取るとき、通常は次のようにします。

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

while9行目の-loopを見てください。そこで、新しい行が読み取られて変数に格納され、次にループの内容が実行されます。これはifステートメントではないことはわかっていますが、whileループも質問に含めることができると思います。

これは、を使用するとFileInputStream、を呼び出すたびFileInputStream.readLine()に、ファイル内の次の行を読み取るため、をfileIn.readLine() != null呼び出す代わりに、変数を割り当てずにループから呼び出した(currentLine = fileIn.readLine()) != null場合、ループの内側でも、2行おきにしか取得できません。

ご理解のほどよろしくお願いいたします。


3

Javaのifステートメント内でも割り当てを行うことができます。良い例は何かを読み書きすることです:

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でも実現可能であることを知っておくのは良いことです:)
Michael Mao

その意味はわかりません。Java、PHP、その他多くの言語で実行できます。問題はJavascriptに関するものでした。
pmrotule 2016年

いいえ、必ずしもそうとは限りません。質問を注意深く読み直す必要があります。
Nitrodist 16

3

Martin Fowlersの本「既存のコードのデザインを改善するリファクタリング」を参照するとしたら!次に、それが良い習慣になるいくつかのケースがあります。関数またはメソッドの呼び出しを使用してケースをアサートする長い複雑な条件:

"動機

プログラムの複雑さの最も一般的な領域の1つは、複雑な条件付きロジックにあります。条件をテストし、さまざまな条件に応じてさまざまなことを行うコードを書くと、すぐにかなり長い方法になってしまいます。メソッドの長さはそれ自体が読みにくくする要因ですが、条件によってはさらに難しくなります。問題は通常、条件チェックとアクションの両方のコードが何が起こっているかを通知しますが、なぜそれが起こるのかを簡単に覆い隠すことができるという事実にあります。

大きなコードブロックと同様に、コードを分解し、コードのチャンクをそのコードブロックの意図に基づいて命名されたメソッド呼び出しに置き換えることで、意図をより明確にすることができます。>条件を使用すると、条件部分と代替のそれぞれに対してこれを実行することで、さらにメリットを得ることができます。このようにして、状態を強調表示し、分岐しているものを明確にします。分岐の理由も強調します。」

そして、はい、彼の答えはJava実装にも有効です。例では、変数に条件関数を割り当てません。


1

それは良い習慣ではありません。あなたはすぐにそれについて混乱するでしょう。これは一般的なエラーに似ています。「=」および「==」演算子の誤用です。

2行のコードに分割する必要があります。コードをより明確にするだけでなく、将来のリファクタリングも容易になります。IF条件を変更することを想像してみてください。誤って行を削除すると、変数に値が割り当てられなくなります。


@thethanghn:まさに私が恐れていること。年を取って怠惰になったとき、キーストロークを少なくするだけで十分であれば、コードにこれ以上入力したくありません:)
Michael Mao

1
いいえ、混乱することはなく、いつもそうしています。それには利点があります。
JDrake 2017年

それは本当に依存しますよね?'C'の背景(およびCに基づく他の言語)の出身である場合、構成は非常によく知られており、代替手段は非常に扱いにくいものです。IMO、それは一度学んだことです。何度もつまずくようなものではありません。
マックスウォーターマン

0

私はこれを昔ながらのCスタイルと考えています。JavaScriptでは実際には良い方法ではないため、回避する必要があります。


8
Cでも良い習慣だとは思いません。
Matthew Crumley、2010

1
私はそれを多くの言語で良い習慣だと思います。
JDrake 2017年

「いい練習じゃない」って言うだけでは十分じゃないよ、イモ。それは本当に教育に関するものです-それは一度学んだことがあり、それだけです。
マックスウォーターマン


0

私はgolangから来ました。

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

これではerrそれにスコープされるifブロックのみ。そのため、これはes6で実行していることです。これはかなり見苦しいように見えますが、かなり厳密なeslintルールを変更せず、同じことを実現します。

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

余分な中括弧は、新しい、ええと、「字句スコープ」を定義しますか?これは私が使用できることを意味しconst、そしてerr外側のブロックには使用できません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.