質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

Q&A

解決済

3回答

3001閲覧

TypeScript bool値に対してそのまま論理和などの代入演算子を使えるか?

brsice

総合スコア17

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

0グッド

0クリップ

投稿2019/07/13 00:30

編集2019/07/13 00:31

TypeScriptでbool値に"|="を用いたところエラーが発生し、JavaScriptでもbool値に対してビットを操作するタイプの代入演算子を実行すると数値にキャストされていることを知りました。

TypeScript

1let x = false; 2x |= true; // エラー

JavaScript

1let x = false; // x = false 2x |= true; // x = 1

JavaScriptなら数値にキャストされても使う分にはそこまで問題ありませんが、前述の通りTypeScriptではエラーになってしまいます。
もちろん明示的にキャストすればTypeScriptでも使えるのですが、多くの条件に対して論理和や論理積を連続して計算したい場合、毎回キャストするのは面倒に感じます。
かと言って左辺を"x=true"の代わりに"x=1"のように書くのも可読性を下げるような気がしますし、比較する右辺はbool値であることが多いと思うので、やはりキャストは避けられません。
この操作を行いたいときはどのように書くのがスマートでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

こんにちは

2つの booleanである xy があったときに、ビットごとのOR | ではなく論理OR || にも代入演算子があって、

x ||= y

と書くことができて、質問者様の意図しているような代入演算をしてくれたらいいなと思うときが、確かに時々ありますね。ですがこれは代入演算子の一覧

に無く、SyntaxErrorになってしまうので、

TypeScript

1x = x || y

としておくところかなと思います。
以上参考になれば幸いです。

投稿2019/07/13 02:00

編集2019/07/13 02:18
jun68ykt

総合スコア9058

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

brsice

2019/07/13 07:09

回答ありがとうございます。 私も現状そのように実現しています。 これまた同じく「あったら便利なのになぁ」という意図での質問でした。 やはり代入ではなく普通に書くしかなさそうですね。
jun68ykt

2019/07/13 07:43

そうですね。Ruby や Perl だと ||= が使えますので、JavaScript ではなぜ使えないのか、という議論があるだろうと思って、ちょっと探してみたところ、以下がありました。 Why there are no compound assignment operators for logical operators (such as ||, && etc)? https://softwareengineering.stackexchange.com/questions/189479/ 上記の回答を読むと、JavaScript (あるいはECMAScript)の設計者が、 ||= を導入するメリットとデメリットを検討した結果、盛り込まないという判断をしたものと思われます。
brsice

2019/07/13 08:52

情報ありがとうございます。 興味深く読ませていただきました。 式として書いているにも関わらず評価されない可能性がある、というのが設計者目線だと必要か不必要か判断が分かれるところでしょうか。 実際TypeScriptにこだわらなければ、場合によっては|=でもほぼ同等の動作が実現できるのもありそうですね。
guest

0

ビット演算子

JavaScript

1let x = false; // x = false 2x |= true; // x = 1

ビット演算子は Number 型の値を返す処理なので、Boolean 型が代入されるコードに違和感を覚えてしまいます(可読性が低いと感じられます)。
元の書き方に準ずるなら、下記コードに書き換えられますが、

JavaScript

1x = x | true;

いずれにしても、Number 型の値が入る問題があります。
ビットを使うなら、私はむしろ、1と0でフラグ管理した方が分かりやすいと感じます。

代入演算子

ご質問の状況なら、私は下記コードを書きます。

JavaScript

1x = true;

結果は同じはずですが、短絡評価に意義があるのなら、

JavaScript

1if (!x) x = true;

と書きます。

配列の各要素に対して順番に論理和

コメントよりコードを引用します。

JavaScript

1x = false; 2for(let i=0; i<10; ++i){ 3x |= isTrue(data[i]); 4}

このコードの場合、

  1. isTrue(data[i]) を実行する
  2. x が truthy なら、代入値は必ず 1
    x が falsy なら、isTrue() の返り値であるBoolean値を Number 型に変換した値 (1 or 0)

となるわけですが、x が truthy であっても、isTrue() が必ず呼び出されてしまうという問題があります。
ですので、私なら前述の通り、if 文を使います。

JavaScript

1'use strict'; 2function isTrue (number) { 3 return number < 100; 4} 5 6function sample1 (data) { 7 let x = false; 8 9 for (let i = 0; i < 10; ++i) { 10 x |= isTrue(data[i]); 11 } 12 13 return x; 14} 15 16function sample2 (data) { 17 let x = false; 18 19 for (let i = 0; i < 10; ++i) { 20 if (!x) x = isTrue(data[i]); 21 } 22 23 return x; 24} 25 26 27function test (args, fn1, fn2) { 28 const result1 = fn1(args), result2 = fn2(args); 29 console.log(result1, result2); 30} 31 32test([1,2,3,100], sample1, sample2); // 1 true 33test([100,101,102], sample1, sample2); // 0 false

break 文を使えば、論理和さえ不要」という考え方もありますが、そこは「別の処理の関係でbreak出来ない」という事にしておきます。

ビット列

今回の命題にはオーバースペックですが、ビット列を利用すると、各要素に対応する flag を一つの変数で管理することが出来ます。

JavaScript

1function sample3 (data) { 2 let x = 0; 3 4 for (let i = 0; i < 10; ++i) { 5 x += isTrue(data[i]) * Math.pow(2, i); 6 } 7 8 return x; 9} 10 11const flags = sample3([100,2,103,4]); 12 13console.log(flags.toString(2)); // 1010

今回の命題としては、

JavaScript

1flags !== 0

が変数 x に期待される値という事になります。

加算演算子

ビット列と同じ理屈で「論理和」を「加算」に置き換える方法もあります。

JavaScript

1for (let i = 0; i < 10; ++i) { 2 x += isTrue(data[i]); 3}

isTrue が Boolean 値を返すなら、x に加算されるのは 0 or 1 です。
x には各要素が truthy だった数が代入され、値が 0 でなければ、論理和が成立している事になります。

※こちらも「無駄にisTrueが実行されてしまう」という問題があるので、論理和だけが必要であれば、if 文を私は使います。

Re: brsice さん

投稿2019/07/13 06:46

編集2019/07/13 09:46
think49

総合スコア18162

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

brsice

2019/07/13 07:36

回答ありがとうございます。 >ビット演算子は Number 型の値を返す処理なので、Boolean 型が代入されるコードに違和感を覚えてしまいます(可読性が低いと感じられます)。 そういう意見もあるのですね、驚きました。 周りにプログラムができる人がおらず他の人の意見を聞くことが全くないので、それが普通の感覚なのかもしれませんが・・・。 確かにビット演算子は数値を返すものですが、大体の言語はbool値と数値は相互変換可能だととらえていいます。 ですので問題なく動作するだろうと思っていたのですが、TypeScriptが思ったより型について厳格でした。 基本的には意味が理解できる範囲で短く書いた方が可読性が高いと思っており、boolと数値の相互変換は問題なく理解できる範囲だという考えです。 回答頂いたコードについてですが、論理和や論理積を繰り返すことを前提としているので、単純な"x=true"は使えません。 ifを使った方は冗長に感じますが、型安全なので選択肢に入れてみます。 ビットによるフラグ管理は好きでよく使うのですが、0と1しかないならbool値を使いたい、というのが正直なところです・・・。
think49

2019/07/13 07:42

> 論理和や論理積を繰り返すことを前提としているので、単純な"x=true"は使えません。 この部分が理解できなかったのですが、例えば、どのようなコードなのでしょうか。
brsice

2019/07/13 07:54

単純な例だと、配列の各要素に対して順番に論理和と計算し、どれか1つでもtrueになれば最終的にxもtrueになる、というような形でしょうか。 このような処理をループではなく1つ1つ書きたいときに、ifではなく代入演算子で書いた方が無駄なネストもなく左辺にbool値が代入された変数が揃って見やすいので他の言語でよく使っていました。
think49

2019/07/13 08:30

> 単純な例だと、配列の各要素に対して順番に論理和と計算し、どれか1つでもtrueになれば最終的にxもtrueになる、というような形でしょうか。 すみませんが、コードで書いて頂けませんか。 「何と何を論理和」しているのか分かりません。 また、言葉で受け取ったコードには齟齬が発生する可能性が高いです。
brsice

2019/07/13 08:42 編集

そうですか、失礼しました。 例えば以下のような形です。 x = false; for(let i=0; i<10; ++i){ x |= isTrue(data[i]); } フラグを保存するためのxと、データを与えるとbool値を返す関数isTrueを用いて、dataの中に1つでもtrueがあれば最終的にxがtrueになります。 すなわち以下と同義です。 x = false; for(let i=0; i<10; ++i){ if(isTrue(data[i])) x = true; }
think49

2019/07/13 09:46

親記事に追記しました。
brsice

2019/07/13 10:55

追記ありがとうございます。 確かに私もこの中ならifを使いたくなります。 意見が分かれる部分かもしれませんが、個人的には通常の論理和を使った方法 (x = x || y) の方が分かりやすく感じます (動作は同じですよね?) 。 完全に個人的な問題ですが、他の言語でこのような処理を行いたいときに評価する右辺はほとんど処理のないようなものばかりだったので、あまり気かけず代入演算子を用いていたのですが、しっかり短絡評価の観点も持つべきでしたね。 このようなケースでは"||="が存在しない限り代入演算子は使わないでおこうと思います。
think49

2019/07/13 11:42

> 個人的には通常の論理和を使った方法 (x = x || y) の方が分かりやすく感じます (動作は同じですよね?) 。 x = x が発生する点を除けば、if (!x) x = y; と等価だと思います。
brsice

2019/07/16 00:34

なるほどx=xのコストがありましたか。 若干違いがあるのですね。
guest

0

どうしても特定の型が必要という状況でなければ、let x: any = true;と型付けを放棄してしまうのも1つの選択肢かもしれません。

投稿2019/07/13 04:18

maisumakun

総合スコア145183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

brsice

2019/07/13 07:13

回答ありがとうございます。 こういうときこそanyの使い所なのかもしれませんね。 TypeScriptを触り始めたばかりなので、どうしても型にはめねばという思いが無駄にありました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問