引数・可変長引数 (arguments)・値渡し/参照渡し・戻り値
デフォルト引数 ・可変長引数

引数・可変長引数 (arguments)・値渡し/参照渡し・戻り値

メモ

  • EcmaScript 2015 (6) 以降では、明示的な 可変長引数 が使用可能
  • 関数定義 と 関数呼び出しの引数の数が不一致でも関数呼び出し可能 (参照)
    • 不足引数:undefined または デフォルト引数 の値
    • 過剰引数:下記 arguments【引数リスト】参照
  • 関数が呼び出されると自動的に arguments 【引数リスト】を作成
    arguments説明備考
    arguments[0~]各引数strict モードでは代入不可
    arguments.callee実行中の関数strict モードでは使用不可 (TypeError例外)
    arguments.caller呼び出した関数 (実装依存)strict モードでは使用不可 (TypeError例外)
    参考:Function.caller【呼び出した関数】 プロパティ
    arguments.length呼び出し時の引数の数引数の定義数はFunction.length【引数の定義数】プロパティ
  • プリミティブ型は値渡し、オブジェクト型は参照渡し (厳密には共有渡し) (参照)
  • 戻り値が未指定の場合、 戻り値は undefined【未定義】 (参照)

【引数の過不足】
function func(x, y) {
  console.log(x, y);
}
// 以下全て呼び出し可能
func(1, 2);     // 出力:1 2
func(1);        // 出力:1 undefined
func();         // 出力:undefined undefined
func(1, 2, 3);  // 出力:1 2
【arguments(引数リスト)】
function func(x, y) {
  console.log("arguments.callee = " + arguments.callee);
  console.log("arguments.caller = " + arguments.caller);
  console.log("arguments.length = " + arguments.length);
  for (var i = 0; i < arguments.length; i++) {
    console.log("arguments[" + i + "] = " + arguments[i]);
  }
  console.log("func.length = " + func.length);
  console.log("func.caller = " + func.caller);
}

function func2(x, y) {
  func(x, y);
}

func(1, 2);
// 出力:arguments.callee = function func(…
// 出力:arguments.caller = 実装依存
// 出力:arguments.length = 2
// 出力:arguments[0] = 1
// 出力:arguments[1] = 2
// 出力:func.length = 2
// 出力:func.caller = null

func(3, 4, 5);  // 関数定義より多い引数
// 出力:arguments.callee = function func(…
// 出力:arguments.caller = 実装依存
// 出力:arguments.length = 3
// 出力:arguments[0] = 3
// 出力:arguments[1] = 4
// 出力:arguments[2] = 5
// 出力:func.length = 2
// 出力:func.caller = null

func2(6, 7);
// 出力:arguments.callee = function func(…
// 出力:arguments.caller = 実装依存
// 出力:arguments.length = 2
// 出力:arguments[0] = 6
// 出力:arguments[1] = 7
// 出力:func.length = 2
// 出力:func.caller = function func2(…
【値渡し/参照渡し (共有渡し)】
function func(bool, num, str, array1, array2, date1, date2, obj1, obj2) {
  console.log(bool);
  console.log(num);
  console.log(str);
  console.log(array1);
  console.log(array2);
  console.log(date1.toISOString());
  console.log(date2.toISOString());
  console.log(obj1);
  console.log(obj2);

  bool = false
  num = 100;
  str = "変更後";
  array1[0] = 10;                           // 変更
  array2 = [10, 20, 30];                    // 新規作成
  date1.setUTCFullYear(2011, (12 - 1), 13); // 変更
  date2 = new Date("2011-12-13T14:15Z");    // 新規作成
  obj1.x = 10;
  obj2 = {x:1, y:2, z:3};
}

var bool = true;
var num = 1;
var str = "変更前";
var array1 = [1, 2, 3];
var array2 = [1, 2, 3];
var date1 = new Date("2001-02-03T04:05Z");
var date2 = new Date("2001-02-03T04:05Z");
var obj1 = {x:1, y:2};
var obj2 = {x:1, y:2};

func(bool, num, str, array1, array2, date1, date2, obj1, obj2);
// 出力:true
// 出力:1
// 出力:変更前
// 出力:[1, 2, 3]
// 出力:[1, 2, 3]
// 出力:2001-02-03T04:05:00.000Z
// 出力:2001-02-03T04:05:00.000Z
// 出力:Object {x: 1, y: 2}
// 出力:Object {x: 1, y: 2}
func(bool, num, str, array1, array2, date1, date2, obj1, obj2);
// 出力:true
// 出力:1
// 出力:変更前
// 出力:[10, 2, 3]
// 出力:[1, 2, 3]
// 出力:2011-12-13T04:05:00.000Z
// 出力:2001-02-03T04:05:00.000Z
// 出力:Object {x: 10, y: 2}
// 出力:Object {x: 1, y: 2}
【未指定の戻り値】
function func1() {
}
function func2() {
  return;
}

console.log(func1()); // 出力:undefined
console.log(func2()); // 出力:undefined

関連

デフォルト引数 ・可変長引数

メモ

  • デフォルト引数
    • 引数の後に省略時の値を記述 (例:p1 = 1, p2 = 2)
    • デフォルト値として前の引数を参照可能 (例:p1 = 1, p2 = p1 + 1)
  • 可変長引数
    • 明示的な記述方法 (例:p1, ...pN)
    • 指定引数は、Array【配列】 (argumentsは疑似配列)
    • 指定引数は、未指定部分の引数配列、可変長引数 (arguments)は全ての引数を含む

【コードによるデフォルト引数】
/**
 * RGB値 取得
 * @param {number} [r=255] 赤色
 * @param {number} [g=255] 緑色
 * @param {number} [b=255] 青色
 * @return {number} RGB値
 */
function rgbA(r, g, b) {
  r = (r === undefined) ? 255 : r;
  g = (g === undefined) ? 255 : g;
  b = (b === undefined) ? 255 : b;
  return r * 0x10000 + g * 0x100 + b;
}

console.log(rgbA().toString(16));             // 出力:ffffff
console.log(rgbA(64).toString(16));           // 出力:40ffff
console.log(rgbA(64, 128).toString(16));      // 出力:4080ff
console.log(rgbA(64, 128, 192).toString(16)); // 出力:4080c0

【デフォルト引数 /**
 * RGB値 取得
 * @param {number=} r 赤色
 * @param {number=} g 緑色
 * @param {number=} b 青色
 * @return {number} RGB値
 */
function rgbB(r = 255, g = 255, b = 255) {
  return r * 0x10000 + g * 0x100 + b;
}

console.log(rgbB().toString(16));             // 出力:ffffff
console.log(rgbB(64).toString(16));           // 出力:40ffff
console.log(rgbB(64, 128).toString(16));      // 出力:4080ff
console.log(rgbB(64, 128, 192).toString(16)); // 出力:4080c0
【引数をデフォルト引数に指定】
/**
 * 合計値 取得
 * @param {number} p1 パラメータ1
 * @param {number} [p2=p1+1] パラメータ2
 * @param {number} [p3=p2+1] パラメータ3
 * @return {number} 合計値
 */
function sumA(p1, p2 = p1 + 1, p3 = p2 + 1) {
  console.log("sumA:", p1, p2, p3);
  return p1 + p2 + p3;
}
console.log(sumA(1));
// 出力:sumA: 1 2 3
// 出力:6
console.log(sumA(2));
// 出力:sumA: 2 3 4
// 出力:9
console.log(sumA(1, 2));
// 出力:sumA: 1 2 3
// 出力:6
console.log(sumA(1, 3));
// 出力:sumA: 1 3 4
// 出力:8
console.log(sumA(1, 2, 3));
// 出力:sumA: 1 2 3
// 出力:6
console.log(sumA(2, 4, 6));
// 出力:sumA: 2 4 6
// 出力:12
【可変長引数 (arguments)】
/**
 * 合計値 取得
 * @param {...number} p1 
 * @return {number} 合計値
 */
function sumB(p1) {
  var answer = 0;
  for (var i = 0; i < arguments.length; i++) {
    answer += arguments[i];
  }
  return answer;
}
console.log(sumB(1, 2, 3));       // 出力:6
console.log(sumB(1, 2, 3, 4, 5)); // 出力:15

【可変長引数 /**
 * 合計値 取得
 * @param {number} p1 
 * @param {...number} pN
 * @return {number} 合計値
 */
function sumC(p1, ...pN) {
  console.log("sumC:arguments.length = " + arguments.length);
  console.log("sumC:pN.length = " + pN.length);
  var answer = p1;
  for (var i = 0; i < pN.length; i++) {
    answer += pN[i];
  }
  return answer;
}

console.log(sumC(1, 2, 3));
// 出力:sumC:arguments.length = 3
// 出力:sumC:pN.length = 2
// 出力:6
console.log(sumC(1, 2, 3, 4, 5));
// 出力:sumC:arguments.length = 5
// 出力:sumC:pN.length = 4
// 出力:15

関連