🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
ECMAScript

ECMAScriptとは、JavaScript類の標準を定めるために作られたスクリプト言語です。

JavaScript

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

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

Q&A

解決済

3回答

832閲覧

Arrow functionで、あえて引数にundefinedを渡したことを識別する方法はあるのか

maisumakun

総合スコア145975

ECMAScript

ECMAScriptとは、JavaScript類の標準を定めるために作られたスクリプト言語です。

JavaScript

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

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

1グッド

4クリップ

投稿2020/12/25 03:32

ES6以上にあるArrow functionを(param) => { /* 中身略 */ }のように書いた場合に、「paramを省略して呼び出した場合」と「paramundefinedを指定した場合」を区別する方法はありますでしょうか。

なお、実用的にはそのような関数を書くべきではないでしょうし、どうしても必要となれば「functionで書いてarguments.lengthをチェックする」「...argsのように書いて、args.lengthをチェックする」などに書き換えれば動かすことは可能だということは間違いないです。

あと、以下の方法はうまくいかないことも把握しています。

  • arguments.length…Arrow functionではargumentsを取れない
  • デフォルト引数を付ける…あえてundefinedを渡してもデフォルト引数が適用される
A_kirisaki👍を押しています

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

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

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

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

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

A_kirisaki

2020/12/25 12:32

これ英訳・追記して Stack Overflow 持ってってもいいですか?
maisumakun

2020/12/25 12:36

はい、こちらにリンクと、あとフィードバックもいただければ大丈夫です
guest

回答3

0

ベストアンサー

arguments#length の代替手段

Arrow functionで、あえて引数にundefinedを渡したことを識別する方法はあるのか

同じ疑問を持って調べた事がありますが、私が調べた範囲ではアロー関数に arguments#length の代替手段はありませんでした。

残余引数(Rest parameters)

「...argsのように書いて、args.lengthをチェックする」

確かにこの方法でも実引数の数を参照できますが、Function#length 値を0にリセットする問題があり、厳密には arguments#length の代替手段になりません。

JavaScript

1function fn1 (arg) { console.log(arguments.length); } 2const fn2 = (...args) => console.log(args.length); 3 4console.log(fn1.length); // 1 5console.log(fn2.length); // 0

残余引数(Rest parameters)は二通りの使い道があります。

  • 可変引数を指定する
  • Function#length 値をコントロールする為にoptionalな引数に指定する

JavaScript

1function output (value, ...option) { 2 console.log(option[0] ? String(value) : value); 3} 4 5console.log(output.length); // 1

関数 output の必須パラメータは第一引数であり、残余引数(Rest parameters)を使用することで output.length 値が 1 になるよう調整できます。

推奨or非推奨

なお、実用的にはそのような関数を書くべきではないでしょうし、れば動かすことは可能だということは間違いないです。

これには異論があります。
例えば、関数の多重定義(オーバーロード)を実装する場合、ECMAScriptには標準機能が存在しない為、arguments,length を活用する必要があります。

JavaScript

1function overloadFunction () { 2 switch (arguments.length) { 3 case 0: 4 throw new Error('One or more arguments required'); 5 case 1: 6 // 実引数が1個の処理 7 break; 8 case 2: 9 // 実引数が2個の処理 10 break; 11 case 3: 12 default: 13 // 実引数が3個以上の処理 14 break; 15 } 16}

また、Function#length を利用した必須パラメータを判定する為にも arguments.length は有効です。

JavaScript

1function sum (a, b) { 2 let i = arguments.length; 3 4 if (i < sum.length) { 5 throw new Error(sum.length + ' or more arguments required'); 6 } 7 8 let result = 0; 9 10 while (i--) result += +arguments[i]; 11 12 return result; 13} 14 15sum(1,2); // 3 16sum(1); // Error: 2 or more arguments required

ECMAScript 2020

ECMAScript 2020 には実引数の数に関連したErrorオブジェクトが存在しません。

実引数の数が不足した事に起因するエラーは大抵、TypeErrorになります。

JavaScript

1[].forEach(); // TypeError: undefined is not a function

ビルトイン関数の基本的な動きは

  1. 引数の型をチェック
  2. 引数の型が実行条件を満たさない場合は TypeError を返す

というもので、Undefined 型を要求する関数は(私の知る限りでは)存在しない為、引数の数が不足すれば型チェックによって TypeError を返すケースが大半です。


ただし、それでも例外はあるもので、実引数の数を判定しているビルトイン関数も存在します。

JavaScript

1fetch(undefined); // エラーは発生しない 2fetch(); // TypeError: Failed to execute 'fetch' on 'Window': 1 argument required, but only 0 present.

結論

アロー関数に arguments.length の代替手段はありません。
必要なら「関数宣言or関数式 + arguments.length」を使用し、目的に応じて使い分ける必要があります。

Re: maisumakun さん

投稿2020/12/28 07:01

think49

総合スコア18189

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

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

A_kirisaki

2020/12/28 09:29

JavaScript の雑な実装がみんな悪いんや……。実用的には undefined を未定義動作、それこそ今議論に上がっている引数の不足などに徹底し、その他は null などの値を返すことを徹底するのが落としどころなんですかねえ。TypeScript 使えばそのへんも型でガッチリ固められますし。
think49

2020/12/28 12:01 編集

@A_kirisaki さん > 実用的には undefined を未定義動作 そもそも論に持っていくと、明示的に undefined を引数に指定すべき場面は限られていて、どのような理由で「明示的なundefinedの指定」「未指定によるundefined」を区別すべきなのか、という「実装の理由」「目的」を前提として問うべき問題と思います。 例えば、私が思いつくところでは「Map#setの第一引数」「Function#callの第一引数」がそれです。 その部分は maisumakun さんの質問文から抜けている情報で「実用的にはそのような関数を書くべきではない」も目的を踏まえたうえで適切な実装になっているかを問うべきで、目的を度外視して実装が間違っていると断ずるのは間違っていると私は考えています。 > その他は null などの値を返すことを徹底するのが落としどころ 返り値と本質問の関係性がいまひとつ分からないのですが、undefined と null は本質的に異なる値です。 nullは「Object型が存在しない事を意味する値」であり、未定義値を意味する undefined の代用とはなりません。 http://www.ecma-international.org/ecma-262/11.0/#sec-null-value
guest

0

命題で挙げられていることがほぼ全てでしょう
特定のparamで受ける前提でundefindを引数にするということは
なにも指定していないのと同義ということです。
すでにご自身で理解している通り「(...params)=>{」とすれば
切り分けることも可能です

投稿2020/12/25 04:13

yambejp

総合スコア116694

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

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

yambejp

2020/12/25 04:15 編集

(...params)の反応は残余引数は配列を受けるという性質を利用しています
guest

0

TypeScriptじゃ……ダメ?

追記

TypeScript

1const foo = (value:undefined) => { 2 return value 3} 4 5foo() // compile error

型の上では弾けるようになりましたね。
demo

追記 2

TypeScript

1 2const foo = (x: undefined) => { 3 return x 4} 5 6foo() // compile error 7foo(undefined)

全く使い物になりませんが undefined を取らなければいけない関数はできましたね。型レベルでどうにかこうにかできないか Conditional Types やら持ち出して粘ってみたんですが、実行時に型情報を取得する手段が乏しく上記の判断は難しいのではという判断に至りました。悔しい!

投稿2020/12/25 03:36

編集2020/12/25 10:36
A_kirisaki

総合スコア2853

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

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

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問