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

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

ただいまの
回答率

87.48%

javascriptで同じ名前で複数の関数

解決済

回答 5

投稿

  • 評価
  • クリップ 0
  • VIEW 11K+

score 121

javascriptで下記の様な事は出来るでしょうか。
名前が同じで、引数の数が違う関数です。

//合計の計算
function calcSum(n1, n2){
  return n1 + n2;
}

//合計の計算
function calcSum(n1, n2, n3){
  return n1 + n2 + n3;
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

checkベストアンサー

+6

残念ながら、JavaScriptで同じ名前の関数を複数宣言することはできません。

ただ、いくつか代替となる手段はあります。

// 引数の個数を見分ける
// 引数の個数で違う動きをする場合におすすめ
function calcSum1(n1, n2, n3) {
  if(arguments.length === 2) {
    // 2個の場合の処理
  }
  if(arguments.length === 3) {
    // 3個の場合の処理
  }
}

// 「引数全部処理したい場合」、以下2つのような手もある
function calcSum2() {
  var ret = 0;
  for(var i = 0; i < arguments.length; i++) {
    ret += arguments[i];
  }
  return ret;
}

// ES6(現状では環境を選ぶ)
function calcSum3(...args) {
  // argsは本物の配列
  return args.reduce((total, current) => total + current, 0);
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/18 18:00

    ご回答有難うございました。
    argumentsを利用すると引数を宣言する必要性が薄れるように感じました。
    勿論、宣言しておいた方が可読性は高まると思いますが。

    キャンセル

  • 2017/11/18 18:10

    babelやNode前提の環境では、(同種の引数を任意個受ける、という状況なら)最後のようにspread引数として宣言しておくのがわかりやすい気もします。

    キャンセル

+3

別オブジェクトのメソッドにするとか。

var a = {};
var b = {};
a.calcSum = function ( n1, n2 ) {
    return n1 + n2;
}
b.calcSum = function ( n1, n2, n3 ) {
    return n1 + n2 + n3;
}
console.log( a.calcSum( 1, 2 ) );
console.log( b.calcSum( 1, 2, 3 ) );

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/18 18:04

    ご回答有難うございました。

    console.log(s2.calcSum(n1, n2));
    console.log(s3.calcSum(n1, n2, n3));

    などと書くと分かり易そうですね。

    また、別オブジェクト(クラス)で同じ関数名の処理を行うことはありそうですね。

    キャンセル

  • 2017/11/18 18:57

    あー…なるほど!
    ポリモーフィズムの話だったんですね。
    そう考えれば良い解決方法の一つですね。

    キャンセル

+3

他回答者の方がもう色々な方法を提示されたので、
私は選択肢の使い分けの目安を示したいと思います。


ご質問のサンプルコードのように、
増えていく引数のが同じで、処理も同じ、単調な変化の場合は、
配列を引数に取ってループの回数を変えるのが一番シンプルです。

次に、引数が2個だと引き算、3個だと足し算、
のように型は同じでも処理を分ける必要がある場合、
IF文を使って分岐させます。

さらに、数を足すのか、文字列を連結するのか、
という風に引数の型が異なる場合、
別のオブジェクトに同名のメソッドを付ける
(ポリモーフィズム)のがオススメです。

なぜかというと、型が違う場合、別系統のデータだから、
別オブジェクトに分けた方が整理しやすいのです。
とくにIF文がネストするような複雑な場合に威力を発揮します。


なお、方向性は違いますが、引数のパターンが単調な場合、
とくに内部のIF文を分けるためのフラグとして引数を使っている場合、
高階関数と部分適用で分ける関数型的な手法も有力です。

この場合、名前を増やす代わりに、引数を減らして整理します。
同名はひとつの手段で、目的はコードの整理だと思うので、選択肢のひとつです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/26 16:13

    回答有難うございます。
    高階関数はjavascript特有ですね。
    使い方が分かれば便利だと思います。
    引数に規則性があれば、その部分は簡易化できそうですね。

    キャンセル

+2

JavaScriptでは同名の関数は1個しか存在出来ません。

関数を定義すると、関数の内部でarguments変数が利用可能になります。
それでよしなに計算し、if文等で処理を分岐させる仕組みを盛り込むことになります。
参考サイト: arguments - MDN

他にも引数が不足していても、余った引数にUndefinedが格納されるだけでエラーにはなりません。

function calcSum(a, b, c) {
  return a + b + c;
}
console.log(calcSum(1, 2, 3)); // 6
console.log(calcSum(1, 2)); // NaN <- ちくしょう!

function calcSum(a, b, c) {
  a = a || 0;
  b = b || 0;
  c = c || 0;
  return a + b + c;
}
console.log(calcSum(1, 2, 3)); // 6
console.log(calcSum(1, 2)); // 3

// ES2015という新しい書き方では、引数の初期値が宣言出来るようになりました。
function calcSum(a = 0, b = 0, c = 0) {
  return a + b + c;
}
console.log(calcSum(1, 2)); // 3

おまけ: 単純操作なら配列操作

calcSumというのは複数の数値を全て足すという処理ですね?
例題なんでアレですが、こういう単純処理ならば配列操作でいけますね。
配列を受け取る関数を作って対応できます。

function calcSum(nums) {
  return nums.reduce(function(a, b){return a + b}, 0);
}
console.log(calcSum([])); // 0
console.log(calcSum([1])); // 1
console.log(calcSum([1, 2])); // 3
console.log(calcSum([1, 2, 3])); // 6
console.log(calcSum([1, 2, 3, 5, 5])); // 16

argumentsと配列操作を使ってかっこよく仕上げます。
自動的に宣言されるargumentsは配列っぽい変数ですが、配列から継承して作られた存在ではなく、
リスト操作のメソッドを使おうとするとエラーが出ます。

参考サイト: [JavaScript] arguments をサクッと配列に変換する方法

function calcSum() {
  var args = Array.prototype.slice.call(arguments);
  return args.reduce(function(a, b){ return a + b }, 0);
}
console.log(calcSum()); // 0
console.log(calcSum(1)); // 1
console.log(calcSum(1, 2)); // 3
console.log(calcSum(1, 2, 3)); // 6
console.log(calcSum(1, 2, 3, 4)); // 10

おまけのおまけ!: ES2015をフルに使った場合

maisumakun:
babelやNode前提の環境では、(同種の引数を任意個受ける、という状況なら)最後のようにspread引数として宣言しておくのがわかりやすい気もします。

JSも幾つかバージョンがあり、ES2015という新バージョンでは更に強化した記述が可能になりました。
アロー演算子、spread、reduceをフル活用すれば質問文の例題を1行で書けてしまいます。
残念ながらIE11では対応していませんが、他のモダンブラウザ全てとNode.jsでは扱えますので調べてみてください。

IE11に対応する場合、Babelという古いJSのバージョンに戻すソフトを使えば大体動作します。
自動化ツールを組んで、書いたコードをデプロイ前にBabelを通して反映するということが可能です。

const calcSum = (...nums) => nums.reduce((a, b) => a + b, 0)
console.log(calcSum()); // 0
console.log(calcSum(1)); // 1
console.log(calcSum(1, 2)); // 3
console.log(calcSum(1, 2, 3)); // 6
console.log(calcSum(1, 2, 3, 4)); // 10

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/26 16:16

    詳しいご解説有難うございました。
    便利な演算子がありますね。
    使いこなせればコードの可動性も上がりそうです。

    キャンセル

+2

 多重定義

JavaScriptに多重定義の仕組みはない為、可変引数コード実装時に使われる機構を活用することになります。
多重定義と同様に関数を分割定義したいのならば、多重定義用の関数を一つ用意してやる必要があります。

function calcSum (n1) {
  switch(arguments.length) {
    case 0:
      throw new Error;
    case 1:
      return n1;
    case 2:
      return calcSum2(n1, arguments[0]);
    case 3:
      return calcSum3(n1, arguments[0], arguments[1]);
  }

  throw new Error;
}

function calcSum2 (n1, n2){
  return n1 + n2;
}

function calcSum3 (n1, n2, n3){
  return n1 + n2 + n3;
}

console.log(calcSum(1));           // 1
console.log(calcSum(1, 2));        // 2
console.log(calcSum(1, 2, 3));     // 4
console.log(calcSum(1, 2, 3, 4));  // Error
console.log(calcSum());            // Error

ここで重要なのは、

calcSum.length === 1; // true

であり、最低一つの引数を要求する事が明確になっている点です。
arguments を使って実引数を参照する事で、 Function#length の値をコントロール出来ます。

なお、ES6 の Rest parameters で同様の実装をするには、次のように書きます。

function calcSum (n1, ...n) {}
console.log(calcSum.length);  // 1

Re: uer03108 さん

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/20 11:45

    ご回答有難うございました。
    必須の引数を関数で定義しておいて、オプション的なものはargumentsで取得すれば、分かり易そうですね。
    vbaでもそうなってたな。

    キャンセル

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

  • ただいまの回答率 87.48%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る