2022年04月05日の日記です


代入の評価順  2022-04-05 20:40:58  コンピュータ

Javascript 豆知識。

というか、仕事で重要になった些細なこと。




演算子には評価順がある。

プログラマなら、だれでも意識することだ。


掛け算 * は、足し算 + よりも先に評価される。

でも、括弧 ( ) をつけると、それが最優先で評価される。


1 + 2 * 3 は 2 * 3 が先に評価されて 7 になるけど、

( 1 + 2 ) * 3 なら、1 + 2 が先に評価されて 9 になる、というようなこと。


まぁ、評価順が不安なら括弧で括っとけ、という話でもある。



じゃぁ、次。

6/3/2 という式があった場合、結果は何になるだろう?


これは、6/(3/2) なのか、(6/3)/2 なのか、という問題だ。

答えは、1 だ。(6/3)/2 になっている。


つまり、評価は左のものが先に行われ、右に進む。


Javascript では、累乗は ** で表される。


2 ** 3 ** 2 はどうなるだろう?

答えは 512 だ。2 ** (3 ** 2) が行われている。割り算の時とは逆で、右から順に評価される。



こうした「同じ演算子が続く場合の評価順」のことを、結合性という。

結合性は、演算子により異なる。




さて、本題。


Javascript では、「代入」も演算結果を持つ。

a = 5 という代入式があった場合、これ全体は、代入された値である 5 が結果になる。

そして、これは右から左に評価される。


a = b = 5 という式では、まず b = 5 が評価され、この結果である 5 が a に代入される。



では、次の式はどうか。


var a=0, b=[];

b[a++] = a++;


念のため書いておくと、a++ というのは「a の内容を値とした後で、a を1増加させる」という演算子だ。

a が 0 の時に a++ と書くと、その式自体は 0 なのだが、その後に a は 1 になっている。



さて、代入式は右から評価されるのだから、まず a++ が実行される。

そして、その結果が b[a++] に代入される。


…と、そう思っていた。


でも、結果は [1] になる。配列の 0 番目に、1 が入っている、という状態だ。

先に b[a++] が評価され、その後で a++ が評価されている。




ちなみに、こんな風に式の中に a++ とかを書くのはお勧めしない。


ここではわかりやすい形で書いているけど、実際には await を使った式の評価でバグが出た。

こんな感じだった。


b[a] = await func();

if(!b[a]) return;


func からの戻り値がない場合、それ以降の処理をしない、というようなプログラムだったのだが、実際には func が値を戻したとしても、return されてしまう。


書いたのは僕ではないのだけど、うまく動かないので相談が来た。


await は javascript に並列実行を引き起こすのだけど、その中で a が書き換えられていた。


それにしても、戻り値は b[a] に入ってすぐ次の行で見ているはずで、納得がいかない。

…と、この時点では思った。先に書いたように、左辺の評価は後になると思っていたからだ。


でも、左辺が先に評価されると考えないとつじつまが合わない。

そこで先のプログラムを書き、左辺の評価が先だと知ったわけだ。




Javascript でわからないことがあったら MDN を見ろ、と僕は思っているのだけど、今この記事を書くために確認していたら、ちゃんと書いてあった。

でも、長い文章の中にさらりと入っているので、気づいてなかった。


演算子の優先順位のページに書いてある。

(どこに書いてあるのか探してみよう。見落としていたのに納得してもらえると思う)



・興味深いのは、結合性や優先順位に関係なく、評価の順序は常に左から右になることです。



「計算」には優先順位があるが、「評価」は常に左から。覚えておこう。





同じテーマの日記(最近の一覧)

コンピュータ

別年同日の日記

10年 花見

21年 家事のおとも


申し訳ありませんが、現在意見投稿をできない状態にしています


戻る
トップページへ

-- share --

0000

-- follow --




- Reverse Link -