この記事は K3 Advent Calendar 2025 15 日目の記事です。
この記事は、C を既に学んだ あなた に向けた、JavaScript 入門ガイドとなっています。この記事の著者は情報科学部の人なので、授業で扱っていない内容が紹介される場合がありますが、ご了承ください。
ただ JavaScript を 1 から学びたいだけなら、MDN のチュートリアルを読んでください。そして、本記事では DOM(HTML) の操作を行わず、ただ JavaScript という言語の解説を行います。
JavaScript と Java は別の言語です!!!!!!
JavaScript とは?
JavaScript は(主として)Web ブラウザ上で動く唯一の言語1で、 主に HTML と CSS ともに、API を通して使われます。JavaScript を使うと、これまで PDF のようにどれだけクリックしても変わらなかった Web ページに、interactive で動的な動きをつけることができます。任意の要素に新しい要素を追加したり、文字の色を変えてみたり、外部と通信してみたり。そして今このページを見ている間にも、JavaScript は裏で動き続けているのです。
そして(広義的な)JavaScript は Web ブラウザ外でも動きます。Node.js と呼ばれるサーバーサイド向けの JavaScript は C と同じように単体で動作します。Web ブラウザで動作する JavaScript は、セキュリティ上の観点から様々な制約が課されています。一方 Node.js ではファイルの入出力やコンソールの操作まで、(セキュリティ的な観点から見ても)様々な良いことや悪いことができるようになります。
本記事では Web ブラウザ上で動作する JavaScript でも Node.js でも動作する国際共通規格 ECMAScript を元に解説を進めていきます。
C 言語との違い
C 言語と JavaScript は本当に全く異なる言語です。
- JavaScript にはポインタが存在せず、アドレスがどこだとかなんとか、にならない
- JavaScript は型がどうでもいい(極論)
- JavaScript ではコンパイルしない(厳密にはするけど)
- JavaScript はオブジェクト指向、C は手続き型言語
こんな感じで、JavaScript は C 言語と比べて色々雑で融通が効きます。
実行環境
今回は OneCompiler というサイトで JavaScript (Node.js) を実行していきます。いきなり Web コンソールを表示しましょう!コンソールに入力しましょう!はちょっと難しいかと思ったので、この方法で行きます。
Hello, world!
何事も Hello, world! を表示させるところから始まります。いきなり以下のコードを実行してみましょう。
console.log("Hello, world!");
「Hello, world!」が出力されましたか? JavaScript では Console API の console.log を使用してコンソールに出力します。
あれっ? main 関数 も無いし、#include もしていないのに、出力ができる?と思ったそこの貴方、そうです。 JavaScript では最初に実行されるような main 関数という概念は無く、ファイル全体が main 関数 + return 0; に包まれているようなイメージです。そして、JavaScript では多くの機能が元から読み込まれています。JavaScript で #include というか import することは、そんなに無いでしょう。
console.log はだいぶ雑な printf
上で示したように console.log もコンソールに文字を出力しますが、動作は全然違います。 printf は引数として、文字列と %d などに埋め込む値をとります。一方、console.log では関数にどんな値でも渡すことができます。数字でも、文字列でも、後述する配列でも。しかし printf のようにフォーマットする機能はありません。ただ第 1 引数から順番に値を出力していきます。
じゃあ、printf と同等の機能を使うにはどうすればいい?
そんなときに、テンプレートリテラルという構文を用います。これによって、文字列の間に数値や別の文字列を埋め込むことができますね!
int main(void){
printf("1 + 2 = %d\n", 3);
printf("0.125 * 2 = %f\n", 0.25)
return 0;
}
console.log(`1 + 2 = ${3}`);
console.log(`0.125 * 2 = ${0.25}`);
テンプレートリテラル `` で囲み、埋め込む値の部分は${}で表現します。
ちなみに、既にお気づきかもしれませんが、console.log は自動で \n を付け足します。
コメント
C 言語と同じです! // も /* */ も使えます。
変数の宣言と代入
いよいよ変数に値を代入していきます!冒頭に書いたように、JavaScript では型関係が雑です。数値でも、文字列でも、全て同じ予約語を使用して宣言します。
let a = 1;
const b = 2;
JavaScript では let または const を使用して使う変数を宣言します。
他にも var が存在しますが、これは古い書き方であり巻き上げの発生や再宣言が許可される点など、様々な問題点が存在します。代わりに let を使用するようにしてください。
また、var let const を使わず a = 1 と書くことはできますが、これは使わないで!!!
以下の語は変数名に使用することができず、予約語となっています。(つまり、これらを使う構文が存在するということですね!)
await break case catch class const continue debugger default delete do else export extends false finally for function if import in instanceof let new null return static super switch this throw true try typeof var void while with yield
let と const の違い
let は再代入が許可されますが、const は宣言時に代入された値を変更できません。じゃあ const は何が良いんだという話になりますが、慣れると const を自然と使う体になっていきます。
その究極体が「const教」という宗教となるのです。
いろんな組み込み型
JavaScript で使われる様々な型のおはなし
数値 Number
C には float だとか double だとか int だとか int32_t だとか存在しますが、JavaScript には Number 1つしか存在しません。-1.2 でも 15 でも 5000000000000000 でも Number です。JavaScript の数値型は double 型で管理されます。丸め誤差が発生し放題です!やったね!2
演算子
C とほぼ同じです!! i++ も c += 2 も使えます。下の構文は、全て実際に使用することができます。
x = x / 2;
++x;
x++;
x += 1;
array[x += 1] = 2;
C の演算子一覧 に記載されている演算子は、以下の表にある例外を除いて全て利用できます。
| 演算子名 | 表記 | 使えない理由 |
|---|---|---|
| 間接メンバ | -> |
ポインタが存在しないため |
| 記憶量 | sizeof |
需要がないため |
| アドレス | & |
ポインタが存在しないため |
| 間接参照 | * |
ポインタが存在しないため |
| キャスト | ( 型指定 ) |
勝手にやってくれるため |
ちなみに、<< や & などのビット演算子は 32bit の整数型として処理されます。
比較演算子
== や != などで比較した結果、返ってくるのは int 型ではなく Boolean 型となります。これは、イメージ的には 1 ビットしか保存できない int 型 です。0 は false 、 1 は true と呼ばれます。
const a = (1 == 1);
console.log(a); // -> true
const b = (2 != 2);
console.log(b); // -> false
等価演算子 == と不等価演算子 !=
これら、なんと型が違っても勝手にキャストして評価します。
const a = (123 == "123");
console.log(a); // -> true
const b = (1 == true);
console.log(b); // -> true
厳密に型も同じかどうかを判断するには、=== と !== を使います。ちょっと無理やりな感じがするね。
const a = (123 === "123");
console.log(a); // -> false
const b = (1 === true);
console.log(b); // -> false
文字列 String
C 言語では char 型の配列として扱いますが、JavaScript では文字列型が存在します。'' または "" で囲んで文字列を表現します。そして、喜んでください。文字列の結合が簡単にできます!!!!!!!!そして、文字列の長さは .length から取得することができます。
let a = 'あいうえお' + "かきくけこ\nさしすせそ\tたちつてと";
console.log(a);
// あいうえおかきくけこ
// さしすせそ たちつてと
let b = "いちにさん" + 456 + 'なな';
console.log(b); // -> いちにさん456なな
console.log(a.length); // -> 10
筆者は "" 派なので今後は全て "" を使用していますが、'' でも変わりません。
以下のようにして、文字列に対してさまざまな処理を施すことができます。
| 用途 | JavaScript |
|---|---|
| 文字列に変換 | target.toString() |
| 任意の位置の文字を取得 |
target[位置] *1 |
| 指定範囲を取得 | target.slice(開始位置, 終了位置) |
| 右側の空白を削除 | target.trimStart() |
| 左側の空白を削除 | target.trimEnd() |
| 左右の空白を削除 | target.trim() |
| 指定の文字で区切って配列にする | target.split(文字) |
| 置き換え(ひとつだけ) | target.replace(old, new) |
| 置き換え(全て) | target.replaceAll(old, new) |
*注釈:
- JavaScript の文字列は UTF-16、つまり内部的に 2 バイトの数値の配列として管理されるため、
"𠮷𠮾"などの UTF-16 外の文字をそのまま取得しようとすると、予想外の数値や文字が返されます。詳細は JavaScriptにおけるサロゲートペアとは を確認してください。対処法については JavaScriptで文字列の長さを正しくカウントする を参考にしてください。
配列 Array
JavaScript の配列は、{} ではなく [] で囲んで定義します。このとき、malloc, free がなんだとか、型がなんだとか、長さがなんだとか、指定しなくても JavaScript 側が良いようにやってくれます。そして、配列の中身を取り出すときもメモリのアドレスがどうとか、まっったく考えなくても良いのです。 配列の中身も異なる型を混在させて OK 、配列に配列を入れても、配列内の配列に配列を入れても大丈夫です。(これは多次元配列と言われます)
const hairetsu1 = [1, "a", "wawawawa", 1234567, 0, "← おもしろい"];
console.log( hairetsu1[0] ); // -> 1
console.log( hairetsu1[1] ); // -> a
const hairetsu2 = [ [1, 2, 3], ["あいう", "ABC"], "えーびーしー" ];
console.log( hairetsu2[1] ); // -> ["あいう", "ABC"]
console.log( hairetsu2[1][0] ); // -> あいう
console.log( hairetsu2[1][0][2] ); // -> う
そして、配列には便利な機能が備わっています。そして朗報です!JavaScript では、配列の長さをわざわざ argc などで別に保存しなくても大丈夫なんです! 他にも、簡単に後から要素を追加したり、削除したりできます!
const argv = ["taskkill", "/f", "/im"];
console.log(argv.length); // 配列の長さ 3
argv.push("explorer.exe");
console.log(argv); // -> ["taskkill", "/f", "/im", "explorer.exe"]
argv.splice(1, 0, "/t");
console.log(argv); // -> ["taskkill", "/t", "/f", "/im", "explorer.exe"]
const name = argv.pop();
console.log(argv); // -> ["taskkill", "/t", "/f", "/im"]
console.log(name); // pop により取り出されたもの explorer.exe
console.log(argv.length); // 配列の長さ 4
以下のように様々な機能が利用できます。
| 用途 | JavaScript |
|---|---|
| 要素の取得 | target[位置] または .at(位置) |
| 要素の範囲取得 | target.slice(開始, 終了) |
| 先頭へ挿入 | target.unshift(x1, x2, ...) |
| 先頭の削除 | target.shift() |
| 最後尾へ追加 | target.push(x1, x2, ...) |
| 最後尾の削除 | target.pop() |
| 任意位置へ挿入 | target.splice(位置, 0, x) |
| 任意位置の削除 | target.splice(位置, 1) |
| 配列同士の結合 | target.concat(配列) |
| 要素の全削除 | target.splice(0, target.length) |
| 要素の検索 | target.indexOf(x) |
| 要素のソート | target.sort(比較関数) * |
| 要素を逆順に | target.reverse() |
| 要素の存在確認 | target.includes(要素) |
| 要素をフィルタ | target.filter(フィルタ関数) |
| 全要素が条件に合致するか | target.every(x => xの条件式) |
| 多次元配列の平坦化 | target.flat() |
*注釈:
.sort() だけでも使用できますが、これだと .sort が勝手に要素を文字列に変換してソートします。[6, 24, 4, 104].sort() を実行してみると、大変なことになります。数値の比較には比較用の関数を入力する必要があります。
ちなみに、上記のように const で定義された配列は、配列の中身まで変更不可になるわけではありません。 再代入が許可されず配列そのものを変更できないだけで、長さや中身を変更することは可能です。
Array に関して詳しく知りたい場合は以下を参照してください。
参照先がなくなった変数の値は、Garbage Collection といって JavaScript が自動的にメモリを free します。
辞書型 Object
C 言語ユーザーにとって全く新しい Object(オブジェクト)を紹介します。オブジェクトは「名前:値」というペアでさまざまなデータを格納でき、複雑な構造をしたデータを簡単に扱えるようにします。
辞書型は以下のように定義します。name は 法政大学、age は 145... のように対応関係を作っていきます。
const user = {
name: "法政太郎",
age: 145,
country: "JP",
isMale: true
};
定義した辞書型のデータを取り出すには、以下のようにします。
const user = { name: "法政太郎", age: 145, country: "JP", isMale: true };
// 取り出し方 1
console.log(user.name); // -> 法政太郎
console.log(user.age); // -> 145
console.log(user.country); // -> JP
console.log(user.isMale); // -> true
// 取り出し方 2
console.log(user["name"]); // -> 法政太郎
console.log(user["age"]); // -> 145
// (省略)
なんだか C 言語の構造体にアクセスするときと似ていますね!JavaScript では構造体が存在しない代わりに、オブジェクトの値を取り出す方法として . を使用します。. と [] ではやっていることは変わりません。user[key] のように、キー名に変数を使えるかどうか、くらいしか違う点はありません。
ちなみに、キー名には主に3文字列が利用できます。では、試しに辞書型や配列をキーに使うとどうなるか、やってみると...??
上の画像では、辞書 abcdef が文字列の "[object Object]" に、配列 ghijkl が "1,2,3,4,5" に自動変換されていますね。これが JavaScript です。
「無い」という状態 null と 「無い」 undefined
JavaScript には null という型があります。これは「変数が確かに存在しているが、中身がない」という状態を表します。
一方で、JavaScript には undefined という似た概念が存在します。これは「変数自体が存在しない」ことを表します。実際、Object から存在しないキーを取得しようとすると、エラーは出ず undefined が返されます。
const empty = {};
console.log(empty.a); // -> undefined
また、return による返り値が指定されていないときや、return 自体が省略されているときにも実は undefined が返っています。
予約語に undefined はありませんが、グローバル変数に undefined を使うことはできません。また、ローカル変数でも使わないでください。
null は非常に様々な言語で採用されていて、活用方法は多岐に渡ります。ただ、他の言語での null は実際 undefined に相当すると私は勝手に思っています。
関数
C 言語と JavaScript の壁を分厚くしている要因になっている、関数です。C 言語と比べて、比にならないほど柔軟に関数を定義し、使うことができます。
関数の基本
関数は以下のように定義します。返り値や引数の型は指定しなくて大丈夫です。
function hello(name){
return "Hello - " + name + ".";
}
console.log(hello("Taro")); // Hello - Taro.
JavaScript の関数は、数値や文字列などと同じように代入することができます!function 型の値があるようなイメージです。
function hello(name){
return "Hello - " + name + ".";
}
const greeting = hello;
console.log(greeting("Taro")); // Hello - Taro.
無名関数
関数には名前をつけないこともできます。その場合、本当に 123 や "abcdef" のような感覚で使うことになります。
const hello = function (name){
return "Hello - " + name + ".";
};
console.log(hello("Jiro")); // -> Hello - Jiro.
const fun = {
status: "nemui",
hello: function (name){
return "Hello - " + name + ".";
},
seeyou: function (name){
return "See you - " + name + ".";
}
};
fun.hello("Saburo"); // -> Helo - Saburo.
fun.hello("Shiro"); // -> See you - Shiro.
参照渡し
C 言語で引数にアドレスを渡す感覚で、JavaScript でも似たノリのことをすることができます。ここに書いている時間がないのと、あと説明が難しいので以下を参照してください。
引数の数
JavaScript では、引数が多すぎてもエラーにならないし。少なすぎてもエラーになりません。 多すぎた引数は切り捨てられ、指定されなかった引数には undefined が入ります。
function fun(a, b, c, d){
console.log(`Arguments: ${a}, ${b}, ${c}, ${d}`);
}
fun(10, 20, 30);
// -> Arguments: 10, 20, 30, undefined
fun(5, 4, 3, 2, 1);
// -> Arguments: 5, 4, 3, 2
自動型変換
JavaScript といえばこれ! JavaScript では Number や String などの型が自動的に変換されます。下の例をご覧ください。こんなことが起こるなんて、考えられないでしょう??
console.log(10 + "20"); // -> "1020"
console.log("10" - 2); // -> 8
console.log([10] + 1); // -> "101"
console.log(100 * null); // -> 0
console.log("aaa" - 1); // -> NaN
この仕様を活かして、文字列への変換、数値への変換を以下のように書くことができます。
console.log(123 + ""); // -> "123"
console.log("555" - 0); // -> 555
まあこのせいで意図しないタイミングで文字列になったりして、バグの原因になるのですが。
if 文
C 言語と同じ使い方をできます。
if (test === "passed"){
console.log("おめでとう!");
} else if (test === "failed" && feeling === "sad"){
console.log("かなしい");
} else {
console.log("えええええええええええええええ");
}
for 文
おめでとうございます!C 言語とほぼ同じです!!
let str = "";
for (let i = 0; i < 10; i++) {
str += i;
}
console.log(str); // -> 0123456789
for...of 文
ただの for 文だけでなく、配列の中身を一つずつループで回していく構文も存在します。こちらは自分で i などの変数を管理しなくても良いので、便利ですね。
const family = ["papapyon", "sispyon", "bropyon", "meijiro", "mamapyon", "babapyon", "jijipyon"];
for (const rabbit of family){
if (rabbit.slice(-4) === "pyon"){
console.log(`${rabbit} はえこぴょんファミリーです。`);
} else {
console.log(`${rabbit} は誰!?`);
}
}
新しい変数を const let を使って宣言できるし、既存の変数を指定するだけでも可能です。
while 文
C 言語と全く同じです!!!!
const greek = ["alpha", "beta", "gamma", "delta", "epsilon", "zeta", "eta", "theta", "iota"];
while (greek.length){
console.log(greek.shift());
}
do...while 文
C 言語と全く同じです!!!!
let i = 0;
let result = "";
do {
i ++;
result = result + i;
} while (i < 5);
console.log(result); // -> "12345"
C 言語でできるであろう基本的な部分はこれで終わりです。お疲れ様でした!
おまけ: JavaScript で純粋な int 型を利用する
ArrayBuffer を使用して、仮想的なメモリ空間を生成することができます。他の言語ではよく「バイト配列」と呼ばれるらしい。まず、ArrayBuffer を初期化して、1KB のメモリ空間を生成してみましょう。生成には new 演算子を使います。
const buffer = new ArrayBuffer(1000);
console.log(buffer);
// ArrayBuffer {
// [Uint8Contents]: <00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 900 more bytes>,
// byteLength: 1000
// }
全て 0 で埋め尽くされた 1KB のメモリ空間が誕生!ここに様々な操作を加えていきましょう。今回はこの 1KB のメモリ空間を全て 32 ビット符号なし整数値の配列として操作していきます。この場合、まず buffer を引数に取り、Uint32Array を生成します。そして、配列のように値を入れていきます。
const buffer = new ArrayBuffer(1000);
const uint32 = new Uint32Array(buffer);
uint32[0] = 1;
uint32[1] = 257;
uint32[4] = 1234567890;
console.log(uint32);
// Uint32Array(250) [
// 1, 257, 0, 0, 1234567890, 0,
// 0, 0, 0, 0, 0, 0,
// 0, 0, 0, 0, 0, 0,
// 0, 0, 0, 0, 0, 0,
// 0, 0, 0, 0, 0, 0,
// 0, 0, 0, 0, 0, 0,
// 0, 0, 0, 0, 0, 0,
// 0, 0, 0, 0, 0, 0,
// 0, 0, 0, 0, 0, 0,
// 0, 0, 0, 0, 0, 0,
// 0, 0, 0, 0, 0, 0,
// 0, 0, 0, 0, 0, 0,
// 0, 0, 0, 0, 0, 0,
// 0, 0, 0, 0, 0, 0,
// 0, 0, 0, 0, 0, 0,
// 0, 0, 0, 0, 0, 0,
// 0, 0, 0, 0,
// ... 150 more items
// ]
console.log(buffer);
// ArrayBuffer {
// [Uint8Contents]: <01 00 00 00 01 01 00 00 00 00 00 00 00 00 00 00 d2 02 96 49 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 900 more bytes>,
// byteLength: 1000
// }
buffer を見てわかる通り、1234567890 の部分が d2 02 96 49 として保存されていますね。面白いね!!!
こんな感じで、JavaScript バイナリ単位の操作もできちゃいます。
おわり
なにか難しい内容だったり、ここで紹介した内容ではなくても JavaScript 関連でわからないことがあったら、(自称)JavaScript マスター の Discord @looksky495 まで連絡してね!
おつかれさま〜
-
C や C++ をコンパイルした結果である WebAssembly、コンピュータグラフィックスのレンダリング API である WebGL に使われる OpenGL Shading Language、ブラウザ上から GPU の並列処理を利用可能にする WebGPU に使われる WebGPU Shading Language などが存在するが、いずれも JavaScript により実行が管理される。 ↩
-
BigIntという巨大な整数を扱うための型が存在しますが、マイナーな部類であるため今回は省略します。詳細は JavaScriptの数値型完全理解 を参照。 ↩ -
Symbol型も使用することができますが、こちらは少し難しいので省略。詳細は JavaScriptのSymbolとは? を参照。 ↩
