演算子の拡張

この章では、その後の ES6 標準によって追加されたいくつかの演算子を紹介します。

指数演算子

ES2016 では、新しい指数演算子 (**) が追加されています。

2 ** 2 // 4
2 ** 3 // 8

この演算子の特徴の 1 つは、一般的な左結合ではなく右結合です。複数の指数演算子を併用した場合、右端の指数演算子から計算が開始されます。

// 2 ** (3 ** 2) に相当
2**3**2
// 512

上記のコードでは、最初の指数演算子ではなく、2 番目の指数演算子が最初に計算されます。

べき乗演算子を等号と組み合わせて、新しい代入演算子 (**=) を形成できます。

a = 1.5 とします。
**= 2;
// a = a * a; と同等です。

b = 4 とします。
b **= 3;
// b = b * b * b と同等;

連鎖判定演算子

プログラミングの実践では、オブジェクト内の特定の属性を読み取る場合、その属性の上位レベルのオブジェクトが存在するかどうかを判断する必要があることがよくあります。たとえば、プロパティ message.body.user.firstName を読み取る場合、安全に記述する方法は次のとおりです。

//書き方が間違っています
const firstName = message.body.user.firstName || 'デフォルト';

// 正しい書き方
const firstName = (メッセージ
  && メッセージ.ボディ
  && message.body.user
  && message.body.user.firstName) || 'デフォルト';

上記の例では、「firstName」属性はオブジェクトの 4 番目のレベルにあるため、各レベルに値があるかどうかを確認するために 4 回判定する必要があります。

三項演算子 ?: も、オブジェクトが存在するかどうかを判断するためによく使用されます。

const fooInput = myForm.querySelector('input[name=foo]')
const fooValue = fooInput.value : 未定義

上の例では、fooInput.value を読み取る前に、まず fooInput が存在するかどうかを確認する必要があります。

このようなレイヤーごとの判断は非常に面倒なので、ES2020では上記の書き方を簡素化するために「オプション連鎖演算子」?.を導入しています。

const firstName = message?.body?.user?.firstName || 'デフォルト';
const fooValue = myForm.querySelector('input[name=foo]')?.value

上記のコードは、「?.」演算子を使用して、チェーン呼び出し中に左側のオブジェクトが「null」であるか「未定義」であるかを直接判断します。そうである場合、操作は続行されず、「未定義」が返されます。

以下は、オブジェクトメソッドが存在するかどうかを判定し、存在する場合は即座に実行する例です。

iterator.return?.()

上記のコードでは、iterator.return が定義されている場合、このメソッドが呼び出されます。それ以外の場合、iterator.return は直接 unknown を返し、?. 以降の部分は実行されません。

この演算子は、実装されていない可能性のあるメソッドに特に役立ちます。

if (myForm.checkValidity?.() === false) {
  // フォームの検証に失敗しました
  戻る;
}

上記のコードでは、古いブラウザのフォームオブジェクトに checkValidity() メソッドが存在しない可能性があり、この場合、?.演算子は undefine を返し、判定文は unknown === false となります。 ` なので、次のコードはスキップされます。

連鎖判定演算子「?.」の書き方は3通りあります。

  • obj?.prop // オブジェクトのプロパティは存在しますか?
  • obj?.[expr] // 上記と同じ
  • func?.(...args) // 関数またはオブジェクトのメソッドが存在するかどうか

以下は obj?.[expr] の使用例です。

let hex = "#C0FFEE".match(/#([A-Z]+)/i)?.[1];

上記の例では、文字列の match() メソッドは、一致するものが見つからない場合は null を返します。一致するものが見つかった場合は、?. 演算子が判定の役割を果たします。

以下は、?. 演算子の一般的な形式と、この演算子が使用されない場合の同等の形式です。

a?.b
// と同等
a == 未定義 : a.b

斧]
// と同等
a == null ? 未定義: a[x]

a?.b()
// と同等
a == null ? 未定義: a.b()

あ?.()
// と同等
a == 未定義 : a()

上記のコードでは、最後の 2 つの形式、ifa?.b()a?.() に特に注意してください。 a?.b()a.b に値があるが、関数ではないため呼び出すことができない場合、a?.b() はエラーを報告します。同じことが a?.() にも当てはまります。 anull または unknown ではなく、関数でもない場合、 a?.() はエラーを報告します。

この演算子を使用する場合は、いくつかの注意事項があります。

(1) 短絡のメカニズム

本質的に、「?.」演算子は短絡メカニズムと同等であり、条件が満たされない限り、実行は続行されません。

a?.[++x]
// と同等
a == null ? 未定義 : a[++x]

上記のコードでは、「a」が「unknown」または「null」の場合、「x」はインクリメントされません。つまり、連鎖判定演算子が true になると、右側の式は評価されなくなります。

(2) 括弧の影響

属性チェーンに括弧がある場合、チェーン判定演算子は括弧の外側には影響せず、括弧の内側にのみ影響します。

(a?.b).c
// と同等
(a == null ? 未定義 : a.b).c

上記のコードでは、「?.」は括弧の外側には影響を与えません。「a」オブジェクトが存在するかどうかに関係なく、括弧の後の「.c」は常に実行されます。

一般に、「?.」演算子を使用する場合は括弧を使用しないでください。

(3) エラー報告の機会

以下の書き込み方法は禁止されており、エラーが報告されます。

//コンストラクタ
新しいですか?.()
新しい a?.b()

// 連鎖判定演算子の右側にテンプレート文字列がある
は?.`{b}`
a?.b`{c}`

// 連鎖判定演算子の左辺はスーパー
素晴らしい?。()
スーパー?.フー

//チェーン演算子は代入演算子の左側で使用されます
a?.b = c

(4) 右辺は 10 進数値であってはなりません

前のコードとの互換性を確保するために、foo?.3:0foo ? .3 : 0 に解析されることが許可されているため、?. の後に 10 進数が続く場合は次のように規定されています。 ?. は解析されなくなります。これは完全な演算子とみなされ、三項演算子に従って処理されます。つまり、小数点は次の 10 進数に属して 10 進数を形成します。

Null判定演算子

オブジェクトのプロパティを読み取るときに、プロパティの値が「null」または「unknown」の場合、それらのデフォルト値を指定する必要がある場合があります。一般的な方法は、「||」演算子を使用してデフォルト値を指定することです。

const headerText = response.settings.headerText || 'こんにちは、世界!';
const animeDuration = 応答.設定.animationDuration || 300;
const showSplashScreen = 応答.settings.showSplashScreen || true;

上記の 3 行のコードはすべて || 演算子を通じてデフォルト値を指定していますが、これは書き方が間違っています。開発者の本来の意図は、プロパティの値が null または unknown である限り、デフォルト値が有効になることですが、プロパティの値が空の文字列、false または 0 の場合、デフォルト値も有効になります。

この状況を回避するために、ES2020 では新しい Null 判定演算子 ?? を導入しています。これは || のように動作しますが、演算子の右側の値は、演算子の左側の値が null または unknown の場合にのみ返されます。

const headerText = response.settings.headerText ?? 'こんにちは、世界!';
const animeDuration = 応答.設定.animationDuration ?? 300;
const showSplashScreen = response.settings.showSplashScreen ?? true;

上記のコードでは、デフォルト値は、左側のプロパティ値が「null」または「unknown」の場合にのみ有効になります。

この演算子の 1 つの目的は、連鎖判定演算子 ?. と組み合わせて使用​​して、null または unknown 値のデフォルト値を設定することです。

const animeDuration = response.settings?.animationDuration ?? 300;

上記のコードでは、response.settingsnull または unknown の場合、または response.settings.animationDurationnull または undefined の場合、デフォルト値 300 が返されます。つまり、このコード行には 2 つのレベルの属性の判断が含まれています。

この演算子は、関数パラメーターに値が割り当てられているかどうかを判断するのに非常に適しています。

functionComponent(props) {
  const Enable = props.enabled ?? true;
  //…
}

上記のコードは、props パラメータの enabled 属性に値が割り当てられているかどうかを決定します。これは基本的に次の記述と同等です。

functionComponent(props) {
  定数{
    有効: 有効 = true、
  } = 小道具;
  //…
}

?? は本質的に論理演算であり、他の 2 つの論理演算子 && および || との優先順位の問題があり、それらの間の優先順位はどちらが高く、どちらが低いのかが決まります。優先順位が異なると、論理演算の結果も異なることがよくあります。

現在のルールでは、複数の論理演算子を一緒に使用する場合、優先順位を示すために括弧を使用する必要があります。そうでないとエラーが報告されます。

// エラーを報告する
左&&右??
左、中、右
左 || 右
左?? 右

上記の 4 つの式はエラーを報告するため、優先順位を示すかっこを追加する必要があります。

(左 && 中) ??
lhs && (中央 ?? rhs);

(左 ?? 中) && rhs;
lhs ?? (中央 && rhs);

(左 || 中央) ?? 右
左 || (中央 ?? 右);

(左 ?? 右) ||
左?? (中央 || 右);

論理代入演算子

ES2021 では、論理演算子と代入演算子を組み合わせた 3 つの新しい 論理代入演算子 (論理代入演算子) が導入されています。

// または代入演算子
x ||= y
// と同等
x || (x = y)

// および代入演算子
x &&= y
// と同等
x && (x = y)

// NULL 代入演算子
x ??= y
// と同等
x ?? (x = y)

これら 3 つの演算子 ||=&&=??= は、まず論理演算を実行し、その演算結果に基づいて適宜代入演算を実行することに相当します。

それらの用途の 1 つは、変数またはプロパティのデフォルト値を設定することです。

//古い書き方
ユーザー ID = ユーザー ID || 1;

// 新しい書き方
ユーザー ID ||= 1;

上記の例では、user.id 属性が存在しない場合、新しい書き方は古い書き方よりもコンパクトです。

別の例を示します。

関数の例(opts) {
  opts.foo = opts.foo ?? 'バー';
  opts.baz ?? (opts.baz = 'qux');
}

上記の例では、パラメータオブジェクト opts に属性 foo と属性 baz が存在しない場合、これら 2 つのプロパティにはデフォルト値が設定されます。 「Null代入演算子」を使うと一律に以下のように書けます。

関数の例(opts) {
  opts.foo ??= 'バー';
  opts.baz ??= 'qux';
}

#!コマンド

Unix コマンド ライン スクリプトはすべて、Shebang または Hashbang とも呼ばれる #! コマンドをサポートしています。このコマンドはスクリプトの最初の行に配置され、スクリプトの実行者を指定するために使用されます。

たとえば、Bash スクリプトの最初の行です。

#!/bin/sh

Python スクリプトの最初の行。

#!/usr/bin/env Python

ES2023 では、JavaScript スクリプト用の #! コマンドが導入されており、スクリプト ファイルまたはモジュール ファイルの最初の行に記述されます。

//スクリプトファイルの1行目に記述する
#!/usr/bin/env ノード
'厳密を使用';
コンソール.ログ(1);

//モジュールファイルの1行目に記述する
#!/usr/bin/env ノード
輸出 {};
コンソール.ログ(1);

この行を使用すると、Unix コマンド ラインでスクリプトを直接実行できます。

# スクリプトを実行する以前の方法
$ノードhello.js

#ハッシュバン方法
$ ./hello.js

JavaScript エンジンの場合、「#!」はコメントとして認識され、この行は無視されます。


作者: wangdoc

アドレス: https://wangdoc.com/

ライセンス: クリエイティブ・コモンズ 3.0