{ }codelper

学ぶ › JavaScript

関数 · 14

関数

処理に名前を付けてまとめ、値を受け取って結果を返します。再帰も。

関数は名前の付いたコードのまとまりです。
値(引数)を受け取り、結果を返します。
下の例は、2乗を求める関数と、自分自身を呼ぶ階乗の関数を作って使います。

function square(x) {  return x * x;} function factorial(n) {  if (n <= 1) return 1;  return n * factorial(n - 1);} const n = Number(require("fs").readFileSync(0, "utf8"));console.log(square(n));console.log(factorial(n));
stdin
4
stdout
16
24

ポイント

  • 同じ計算をあちこちで使うときや、長い解答を小さな部品に分けるときに関数にまとめます。
  • return に来ると関数はその場で終わります。
    その下の行は実行されません。
  • 数を渡すと値がコピーされます。
    関数の中で x = 9 と変えても、呼び出し側の変数はそのままです。
  • リストを渡すと同じリストを共有します。
    関数の中で追加すると外でも変わります(C++ の vector は渡すときにコピーされます)。
  • 再帰は関数が自分自身を呼ぶことです。
    大きな問題を同じ形の小さな問題に縮め、必ず止まる条件が必要です(n <= 1 なら 1)。
  • 止まる条件がないか深すぎると、言語によってエラーで止まるか、プログラムごと落ちます。

言語ごとの書き方

Pythondef square(x): とインデント。
return がなければ None を返します。
def が実行されたあとでしか呼べません(先に呼ぶと NameError)。
再帰は既定で約1,000段で RecursionError
JavaScriptfunction square(x) { return x * x; } または const square = (x) => x * x;。
return がなければ undefined。
function 宣言は呼ぶ場所より下にあってもかまいません。
深すぎると RangeError: Maximum call stack size exceeded
TypeScriptJavaScript に型を付けます:function square(x: number): number。
引数の数が違うと型チェックで教えてくれます
Javaクラスの中に static int square(int x)。
返す値がなければ void。
クラスの中ならどこに置いてもかまいません。
深すぎると StackOverflowError
C#Java と同じくクラスの中に static int Square(int x)、返さないなら void。
深すぎる再帰はプログラムごと落ちます
C++int square(int x) のように返す型を前に書き、返さないなら void。
使う前に上で定義するか、int square(int x); で宣言します。
深すぎる再帰はプログラムが落ちます
CC++ と同じです
Craykonキーワードなしで square(x) { 返す x * x; }。
呼ぶ場所より下にあってもかまいません。
数千段を超えると「関数を深く呼びすぎて止まりました」

よくある間違い

引数を渡し忘れたJavaScript

function square(x) { return x * x; }
console.log(square());

→ NaN — 足りない x がエラーなしで undefined で埋められます

値の数を合わせます。
Python(TypeError)、Java・C#・C・C++・TypeScript(コンパイルエラー)、Craykon(「値が2個必要なのに1個しか渡していません」)は教えてくれます。

止まる条件がない

def factorial(n):
    return n * factorial(n - 1)

→ 自分を果てしなく呼び、RecursionError で止まります。ほかの言語もスタックがあふれて止まるか落ちます

先頭に if n <= 1: return 1 のような止まる条件を置きます。

関数の中で変えたのに元が変わらないC++

void add(std::vector<int> v) { v.push_back(9); }

std::vector<int> a = {1};
add(a);

→ a は {1} のまま — コピーに追加しました

元を変えるには std::vector<int>& v のように & を付けます。

言語ごとの違い
階乗はすぐ大きくなります。
32ビットの int には 12! までしか入らないので(Java で int を使って 13! を計算するとエラーなしで 1932053504)、Java・C#・C・C++ の例は64ビットの long/long long(20! まで)を返し、Python には大きさの制限がなく、JavaScript・Craykon は 2^53 を超えると正確でなくなることがあります。

練習問題