AI生成コンテンツ / AI-generated content
目次
サンプル・プログラム
平均を求める
例として、テストの平均点を求めるプログラム "average1.html" を作ってみよう。
左図がプログラムの実行例である。
average1.html
1: <!--
2: /** average1.html
3: * プログラミング入門 - 4.4 配列と引数の渡し方
4: * 合計点・平均点を求める.
5: *
6: * @copyright (c)studio pahoo
7: * @author パパぱふぅ
8: * @動作環境 JavaScript ES6(ES2015)
9: * @参考URL https://www.pahoo.org/e-soul/webtech/js00/js00-04-04.html
10: */
11: -->
12: <!DOCTYPE html>
13: <html lang="ja">
14: <head>
15: <meta charset="UTF-8">
16: <title></title>
17: <script>
18: // 初期値 ==================================================================
19: const TITLE = '合計点・平均点'; //プログラム・タイトル
20: const REFERENCE = 'https://www.pahoo.org/e-soul/webtech/js00/js00-04-04.html';
21: //参照サイト
22: const WIDTH = 300; //表示幅(ピクセル)
23:
24: // ユーザー定義関数 ========================================================
25: /**
26: * ファイル更新日を返す
27: * @param なし
28: * @return String yyyy/mm/dd
29: */
30: function getLastModified() {
31: let now = new Date(document.lastModified);
32:
33: return now.getFullYear() + '/' + (now.getMonth() + 1) + '/' + now.getDate();
34: }
35:
36: /**
37: * 点数表を作成し,画面に表示する.
38: * @param Array scores 点数表(0~100の数値を1個以上含む配列)
39: * @return なし
40: */
41: function dispScoreTable(scores) {
42: const error = document.getElementById('error');
43: const table = document.getElementById('scoreTable');
44: error.textContent = '';
45: table.innerHTML = '';
46:
47: // 0~100点の数値が1個以上入った配列だけを受け付ける.
48: if (!Array.isArray(scores) || scores.length === 0) {
49: error.textContent = 'エラー:正しい点数表を用意してください.';
50: return;
51: }
52: let sum = 0;
53: for (let i = 0; i < scores.length; i++) {
54: const score = scores[i];
55: if (!Number.isFinite(score) || score < 0 || score > 100) {
56: error.textContent = 'エラー:点数には0~100の数値を指定してください.';
57: return;
58: }
59: sum += score;
60: }
61:
62: let html = '<tr><th>出席番号</th><th>点数</th></tr>';
63: for (let i = 0; i < scores.length; i++) {
64: html += `<tr><td>${i + 1}</td><td>${scores[i]}</td></tr>`;
65: }
66: html += `<tr><td>合計点</td><td>${sum}</td></tr>
67: <tr><td>平均点</td><td>${sum / scores.length}</td></tr>`;
68: table.innerHTML = html;
69: }
70:
71: // メイン・プログラム ======================================================
72: window.onload = function() {
73: //タイトル等をセット
74: document.title = TITLE;
75: document.getElementById('title').innerHTML = TITLE + ' <span style="font-size:small;">' + getLastModified() + '版</span>';
76: document.getElementById('reference').innerHTML =`
77: ※参考サイト <a href="${REFERENCE}">${REFERENCE}</a>
78: `;
79:
80: //スタイルシートをセット
81: document.getElementById('help').style.width = WIDTH + 'px';
82: document.getElementById('scoreTable').style.width = WIDTH + 'px';
83:
84: //点数表
85: let scores = [75, 68, 81, 90, 57, 52, 96, 72, 68, 72];
この配列をユーザー定義関数 dispScoreTable に渡し、平均点を求めるとともに、点数一覧表を作成する。
average1.html
36: /**
37: * 点数表を作成し,画面に表示する.
38: * @param Array scores 点数表(0~100の数値を1個以上含む配列)
39: * @return なし
40: */
41: function dispScoreTable(scores) {
42: const error = document.getElementById('error');
43: const table = document.getElementById('scoreTable');
44: error.textContent = '';
45: table.innerHTML = '';
46:
47: // 0~100点の数値が1個以上入った配列だけを受け付ける.
48: if (!Array.isArray(scores) || scores.length === 0) {
49: error.textContent = 'エラー:正しい点数表を用意してください.';
50: return;
51: }
52: let sum = 0;
53: for (let i = 0; i < scores.length; i++) {
54: const score = scores[i];
55: if (!Number.isFinite(score) || score < 0 || score > 100) {
56: error.textContent = 'エラー:点数には0~100の数値を指定してください.';
57: return;
58: }
59: sum += score;
60: }
61:
62: let html = '<tr><th>出席番号</th><th>点数</th></tr>';
63: for (let i = 0; i < scores.length; i++) {
64: html += `<tr><td>${i + 1}</td><td>${scores[i]}</td></tr>`;
65: }
66: html += `<tr><td>合計点</td><td>${sum}</td></tr>
67: <tr><td>平均点</td><td>${sum / scores.length}</td></tr>`;
68: table.innerHTML = html;
69: }
length は配列の長さを表す。この例のように途中が抜けていない配列では、要素の個数と一致する。
forループで合計点を求め、人数で割って平均点を計算し、HTMLの table要素で点数表を表示する。合計は731点、平均は73.1点である。
このサンプルは0~100点の数値を1個以上含む配列を受け付ける。空配列や数値以外の値、範囲外の点数はエラーとして表示する。
数値を渡す:値渡し
parameter1.html
19: <script>
20: // ユーザー定義関数 ========================================================
21: /**
22: * 引数に+1する(その1)
23: * @param Number a
24: * @return Number a + 1
25: */
26: function plus1(a) {
27: let b = a + 1;
28: return b;
29: }
30:
31: /**
32: * 引数に+1する(その2)
33: * @param Number a
34: * @return Number a + 1
35: */
36: function plus2(a) {
37: a = a + 1;
38: document.getElementById('var3').innerHTML = 'a = ' + a.toString();
39: return a;
40: }
41:
42: // メイン・プログラム ======================================================
43: window.onload = function() {
44: let a = 1;
45: document.getElementById('var1').innerHTML = 'A = ' + a.toString();
46: plus1(a);
47: document.getElementById('var2').innerHTML = 'A = ' + a.toString();
48: plus2(a);
49: document.getElementById('var4').innerHTML = 'A = ' + a.toString();
50: }
51: </script>
A = 1表示の大文字 A は呼び出し元の値、小文字 a は関数内の値を区別するためのラベルである。プログラム中の変数名はいずれも小文字の a である。
A = 1
a = 2
A = 1
ユーザー定義関数 plus2 は、関数内の引数 a に1を足して再代入する。関数内では2になるが、呼び出し元の変数 a は plus2 の実行後も1のままである。
数値の引数には、その値が渡される。関数内で引数に再代入しても、呼び出し元の変数は書き換わらない。これが値渡しである。結果を呼び出し元で使うには、戻り値を受け取り、たとえば a = plus1(a) と代入する。
配列を渡す:同じ配列を共有する
A = 1,2,3,4,5
A = 1,2,3,4,5
a = 1,2,3,5,5
A = 1,2,3,5,5
parameter2.html
19: <script>
20: // ユーザー定義関数 ========================================================
21: /**
22: * 配列引数に+1する(その1)
23: * @param Array a 配列
24: * @param Number n 要素番号
25: * @return Number a[n] + 1
26: */
27: function plus3(a, n) {
28: let b = a[n] + 1;
29: return b;
30: }
31:
32: /**
33: * 配列引数に+1する(その2)
34: * @param Array a 配列
35: * @param Number n 要素番号
36: * @return Number a[n] + 1
37: */
38: function plus4(a, n) {
39: a[n] = a[n] + 1;
40: document.getElementById('var4').innerHTML = 'a = ' + a.toString();
41: return a[n];
42: }
43:
44: // メイン・プログラム ======================================================
45: window.onload = function() {
46: let a = [1, 2, 3, 4, 5];
47: let n = 3;
48: document.getElementById('var1').innerHTML = 'A = ' + a.toString();
49: plus3(a, n);
50: document.getElementById('var3').innerHTML = 'A = ' + a.toString();
51: plus4(a, n);
52: document.getElementById('var5').innerHTML = 'A = ' + a.toString();
53: }
54: </script>
ユーザー定義関数 plus4 は、a[n] = a[n] + 1 として、共有している配列の要素を書き換える。n = 3 なので、変更するのは先頭から4個目の要素である。4が5になり、呼び出し元からも変更が見える。
このように、同じオブジェクトを共有する引数の渡し方を共有渡しと呼ぶこともある。「参照渡し」と説明されることもあるが、呼び出し元の変数そのものを関数内から再代入できる方式とは異なる。配列の要素を書き換えることと、別の配列を引数に再代入することは区別しよう。
配列をシャッフルする
shuffle.html
36: /**
37: * 指定した配列をシャフルする.
38: * @param Array arr シャフルしたい配列
39: * @return なし
40: */
41: function shuffle(arr) {
42: for (let i = arr.length; i > 1; i--) {
43: let k = Math.floor(Math.random() * i);
44: [arr[k], arr[i - 1]] = [arr[i - 1], arr[k]];
45: }
46: }
shuffle は元の配列を変更する。元の順番を残したいときは const copy = cards.slice() でコピーを作り、shuffle(copy) とする。このコピーは浅いコピーであり、要素がオブジェクトなら、そのオブジェクトまでは複製されない。
読みやすいプログラム:コメント
AI生成コンテンツ / AI-generated content
コメントは、プログラムの意図を読み手に伝えるために書く。適切な変数名や関数名を付けたうえで、コードだけでは分かりにくい理由や前提を補うとよい。
読みやすいコメントの目安は、何をしているかだけでなく、なぜそうするかを伝えることである。コードをそのまま言い換えるだけのコメントは減らし、初心者が迷う箇所には説明を加える。コードを変更したときは、コメントも見直して食い違いを防ごう。
●コメントに記載する内容
- プログラム使用上の注意、制約条件など。
- プログラム使用にあたって準備すること、実施することなど。
- 参照しているライブラリ、フレームワーク、APIなどの情報。
- プログラムの著作権情報。
- コメントで補足しないと分からないような複雑な箇所。
- 名前から意味が明らかな変数やプロパティへの重複した解説。ただし、単位や制約などは補足する。
- プログラムを読めば分かる内容。ただし、読み手のスキルに応じてコメントを付加すること。
- プログラムの更新履歴。ただし、バージョン管理システムを利用していない場合はコメントとして記述すること。
/**たとえば、次のようなコメントである。
* (1行目)機能概要【必須】
* (2行目)機能詳細,制約事項など【省略可能】
* @param{空白}変数の型{空白}変数名{空白}内容‥‥引数1の説明【省略可能】
* @param{空白}変数の型{空白}変数名{空白}内容‥‥引数2の説明【省略可能】
* (1行に1引数を記述する.)
* @return{空白}変数の型‥‥戻り値の説明【省略可能】
*/
/**
* 点数表を作成し,画面に表示する.
* @param Array scores 点数表
* @return なし
*/
| 関数/メソッド | 機能 | 詳細 |
|---|---|---|
| getLastModified | ファイル更新日を返す | |
| dispScoreTable | 点数表を作成し,画面に表示する. | |
読みやすいプログラム:引数の変更は意図を明確に
AI生成コンテンツ / AI-generated content
また、a = 2 のような代入について「必ず別のメモリ領域を確保する」と考える必要はない。ここでは、JavaScriptの決まりとして観察できる動作を理解しよう。
コラム:完全数を求める
6の約数は1、2、3、6である。自分自身を除くと1+2+3=6となるので、6は完全数である。小さいものから6、28、496、8128が続く。
約数は組で求められる。28なら2と14、4と7が組になるので、候補の平方根まで調べればよい。平方数の平方根は同じ約数を2回足さないようにする。元のサンプルにあった「1から候補の直前まで調べる」処理は、この方法に改めた。
perfectNumbers1.html
23: const RANGE_MIN = 2; //探索範囲の最小値
24: const RANGE_MAX = 100000; //探索範囲の最大値
perfectNumbers1.html
38: /**
39: * 完全数かどうかを判定する.
40: * @param Number num 判定する値
41: * @return Boolean true:完全数である / false:完全数ではない
42: */
43: function isPerfectNumber(num) {
44: if (!Number.isSafeInteger(num) || num < 2) return false;
45: let sum = 1;
46:
47: // 約数を組で探す.たとえば28なら2と14,4と7が組になる.
48: for (let i = 2; i <= Math.sqrt(num); i++) {
49: if (num % i === 0) {
50: sum += i;
51: const pair = num / i;
52: if (pair !== i) sum += pair;
53: }
54: if (sum > num) return false;
55: }
56: return sum === num;
57: }
perfectNumbers1.html
59: /**
60: * 完全数を求める.
61: * @param Number min 探索範囲の最小値
62: * @param Number max 探索範囲の最大値
63: * @return Array: 完全数の配列
64: */
65: function findPerfectNumbers(min, max) {
66: // この入門用サンプルは安全な整数の範囲だけを扱う.
67: if (!Number.isSafeInteger(min) || !Number.isSafeInteger(max)) {
68: throw new RangeError('探索範囲には安全な整数を指定してください.');
69: }
70: if (min > max) return [];
71: let perfectNumbers = []; // 完全数を格納する配列
72:
73: for (let i = Math.max(2, min); i <= max; i++) {
74: if (isPerfectNumber(i)) {
75: perfectNumbers.push(i);
76: }
77: }
78:
79: return perfectNumbers;
80: }
perfectNumbers1.html
95: // 完全数を求める
96: console.time('計算時間'); // 計算時間の計測開始
97: const perfectNumbers = findPerfectNumbers(RANGE_MIN, RANGE_MAX);
98: let ss = '計算範囲:' + RANGE_MIN.toLocaleString() + '~' + RANGE_MAX.toLocaleString() + '<br><br>';
99: console.timeEnd('計算時間'); // 計算時間をconsoleに表示する
100:
101: // 完全数を表示する
102: for (let i = 0; i < perfectNumbers.length; i++) {
103: ss += perfectNumbers[i].toLocaleString() + '<br>';
104: }
105: document.getElementById('results').innerHTML = ss;
10万以下の完全数は6、28、496、8128の4個であり、5個目は33550336である。平方根までの約数探索にしても、探索範囲を広げれば時間がかかり、その間は画面操作が応答しにくくなる。
2026年(令和8年)9月16日に確認した GIMPSの一覧には、既知のメルセンヌ素数が52個載っている。それぞれから偶数の完全数が1個得られる。最大のものの指数は136279841である。メルセンヌ素数の桁数と、それから作る完全数の桁数は異なる。
$$ P = 2^{p - 1} \times (2^p - 1) $$
整数 $ p \geq 2 $ に対し、$ 2^p - 1 $ が素数(メルセンヌ素数)なら、$ P $ は偶数の完全数になる。このとき $ p $ も素数である。ただし、$ p $ が素数でも、$ 2^p - 1 $ が素数になるとは限らない。
perfectNumbers2.html
24: const RANGE_MIN = 2; //探索範囲の最小値
25: const RANGE_MAX = 100000; //探索範囲の最大値
perfectNumbers2.html
39: /**
40: * 素数かどうかを判定する.
41: * @param Number num 判定する値
42: * @return Boolean True:素数である / False:素数ではない
43: */
44: function isPrime(num) {
45: if (!Number.isSafeInteger(num) || num < 2) {
46: return false;
47: }
48: for (let i = 2; i <= Math.sqrt(num); i++) {
49: if (num % i === 0) {
50: return false;
51: }
52: }
53: return true;
54: }
perfectNumbers2.html
56: /**
57: * メルセンヌ素数かどうかを判定する.
58: * @param Number p 2の指数(2~53の整数)
59: * @return Boolean True:メルセンヌ素数である / False:メルセンヌ素数ではない
60: */
61: function isMersennePrime(p) {
62: if (!Number.isSafeInteger(p) || p < 2 || p > 53) return false;
63: let mersenneNumber = Math.pow(2, p) - 1;
64:
65: return isPrime(mersenneNumber);
66: }
perfectNumbers2.html
68: /**
69: * 指定範囲の偶数の完全数を求める.
70: * @param Number min 探索範囲の最小値
71: * @param Number max 探索範囲の最大値
72: * @return Array 偶数の完全数の配列
73: */
74: function findPerfectNumbers(min, max) {
75: // この入門用サンプルは安全な整数の範囲だけを扱う.
76: if (!Number.isSafeInteger(min) || !Number.isSafeInteger(max)) {
77: throw new RangeError('探索範囲には安全な整数を指定してください.');
78: }
79: if (min > max) return [];
80: const perfectNumbers = [];
81: for (let p = 2; ; p++) {
82: const num = Math.pow(2, p - 1) * (Math.pow(2, p) - 1);
83: // 素数判定より先に範囲を確認する.
84: if (!Number.isSafeInteger(num) || num > max) break;
85: if (num >= min && isMersennePrime(p)) {
86: perfectNumbers.push(num);
87: }
88: }
89: return perfectNumbers;
90: }
perfectNumbers2.html
105: // 完全数を求める
106: console.time('計算時間'); // 計算時間の計測開始
107: const perfectNumbers = findPerfectNumbers(RANGE_MIN, RANGE_MAX);
108: let ss = '計算範囲:' + RANGE_MIN.toLocaleString() + '~' + RANGE_MAX.toLocaleString() + '<br><br>';
109: console.timeEnd('計算時間'); // 計算時間をconsoleに表示する
110:
111: // 完全数を表示する
112: for (let i = 0; i < perfectNumbers.length; i++) {
113: ss += perfectNumbers[i].toLocaleString() + '<br>';
114: }
115: document.getElementById('results').innerHTML = ss;
偶数の完全数が無限に存在するかは未解決である。奇数の完全数は、1個でも存在するのかどうかが分かっていない。
2つのサンプルは、JavaScriptの Number型で安全に扱える整数の範囲を対象とする。探索範囲には Number.isSafeInteger() が trueになる整数を指定する。巨大な完全数を求める研究用のプログラムではない。
このように、数学的な性質を利用すると計算を減らせる場合がある。速さだけでなく、どの範囲の答えを求められる方法なのかも確認しよう。
コラム:値渡しと参照の共有
次の例で、配列の要素を変更する場合と、引数に別の配列を再代入する場合を比べよう。
function change(items) {最初の代入は共有している配列の要素を変える。次の代入は、関数内の items が参照する先を変えるだけなので、呼び出し元の original は別の配列に置き換わらない。
items[0] = 9;
items = [100, 200];
}
const original = [1, 2];
change(original);
console.log(original); // [9, 2]
ここで、const で宣言した変数がオブジェクトを参照している場合も確認しよう。
constObject.html
20: <script>
21: //ページのロード時に実行
22: window.onload = function() {
23: // constで宣言したオブジェクト
24: const obj = {
25: a: 1,
26: b: 2,
27: c: 3
28: };
29: document.getElementById('obj').innerHTML = JSON.stringify(obj);
30: document.getElementById('objA1').innerHTML = obj.a;
31: // プロパティに代入
32: obj.a = 9;
33: document.getElementById('objA2').innerHTML = obj.a;
34: // 変数への再代入は失敗する.学習用に例外を捕まえて表示する.
35: try {
36: obj = { a: 0 };
37: } catch (error) {
38: document.getElementById('reassign').textContent =
39: 'objへの再代入:' + error.name;
40: }
41: }
42: </script>
この性質は引数の渡し方とは別の話であり、constで宣言した配列にも同じ考え方が当てはまる。
コラム:インデックスはなぜ0からはじまるのか
C言語のように同じ大きさの要素を連続したメモリに置く配列では、「先頭の住所+インデックス×1要素の大きさ」で位置を表せる。先頭なら加える分は0である。ただし、JavaScriptの Arrayが必ずこの形でメモリに並ぶ、という意味ではない。
0から始めると、長さNの配列を調べる範囲は「0以上N未満」になる。たとえば10個なら0~9であり、forループも次のように書ける。
for (let i = 0; i < scores.length; i++) {途中の範囲も「2以上5未満」なら2、3、4の3個であり、端の差5−2で個数が分かる。ダイクストラも、このような区間の扱いやすさを論じた。
console.log(scores[i]);
}
0始まりは言語の設計上の選択であり、CPUが強制しているわけではない。1始まりを採用する言語もある。「1始まりだと毎回引き算をするので必ず遅い」とも言えない。
参考サイト
- Functions:MDN Web Docs
- Array:MDN Web Docs
- const:MDN Web Docs
- なぜ配列の1番目は「0」なのか? プログラマーなら一度は疑問に思う話:Qiita(コラムの着想・構成を参考にし、原典で補足)
- Why numbering should start at zero(EWD831):E. W. Dijkstra Archive
- List of Known Mersenne Prime Numbers:GIMPS
- Mersenne Primes: History, Theorems and Lists:PrimePages
- Fisher-Yates shuffle:NIST

基本は値渡しである。配列の場合は、配列を参照する値が渡され、呼び出し元と関数が同じ配列を共有する。要素の変更と、変数への再代入を区別することが大切である。
(2026年9月16日)説明とサンプルを訂正し、インデックスのコラムとイラストを更新した。