閉じる

「第一級オブジェクト」って何?身近な例でイメージしながら理解しよう

プログラミングの入門書を読んでいると、ふと現れる「第一級オブジェクト(first-class citizen)」という言葉。

聞き慣れないうえに、説明も抽象的でピンと来ない、と感じたことはないでしょうか。

この記事では、難しい専門用語としてではなく、日常のイメージに結びつけながら「第一級オブジェクトとは何か」を丁寧に解説していきます。

JavaScriptやPythonの具体例も使うので、プログラミング初心者の方でも、自分のコードにどう関係するのかをイメージしながら読める内容になっています。

第一級オブジェクト(first-class citizen)とは何か

プログラミングでの第一級オブジェクトの意味

第一級オブジェクト(first-class citizen)とは、ひと言でまとめると「その言語の中で、ほかの普通の値と同じように自由に扱える存在」のことです。

ここでいう「普通の値」とは、数値や文字列のように、プログラムのあちこちで当たり前のように使っているものをイメージしてください。

たとえば、次のような操作が自然にできます。

  • 変数に代入する
  • 関数の引数として渡す
  • 関数の戻り値として返す
  • 配列やオブジェクトなどのデータ構造に入れる

このような扱いができるものを、そのプログラミング言語では「第一級オブジェクト」と呼びます。

逆に、これらができないものは、その言語では「第一級」ではない、と考えられます。

「値として扱える」がキーワード

第一級オブジェクトを理解するうえでのキーワードは「値として扱える」です。

値として扱える、とは何かを、もう少し噛み砕いてみます。

ふだん、数値や文字列をどのように扱っているかを考えるとイメージしやすくなります。

let x = 10; let y = x; console.log(y); // 10 が表示される

この例では、数値の10を変数xに代入し、それをさらにyに代入しています。

数値10は、変数に入れたり、コピーしたり、関数に渡したり、好きな場所で使える「値」として扱われています。

第一級オブジェクトとは「変数に入れたり、引数として渡したり、戻り値として返したりできる“値”そのものとして扱えるもの」だ、と捉えると理解しやすくなります。

あとで見ていきますが、JavaScriptやPythonでは関数もこの「値」として扱えるので、「関数は第一級オブジェクトです」と説明されます。

初心者が第一級オブジェクトを学ぶメリット

第一級オブジェクトの概念は、一見すると抽象的で、いきなりは必要ないように思えるかもしれません。

しかし、初心者のうちに意味を押さえておくと、次のようなメリットがあります。

1つ目は、ドキュメントや解説記事を読みやすくなることです。

プログラミング言語の公式ドキュメントやライブラリの説明には、「この言語では関数は第一級オブジェクトです」のような記述がよく登場します。

意味が分かっていれば、その周辺の説明全体が理解しやすくなります。

2つ目は、関数の高度な使い方(コールバック、高階関数、イベント処理など)を理解しやすくなることです。

特にJavaScriptやPythonでは、関数を「値」として扱う書き方が頻繁に登場しますが、その背景にあるのが第一級オブジェクトという考え方です。

3つ目は、設計の幅が広がることです。

関数やクラスを「値」として扱えると、ロジックの切り出し方や、責務の分け方が変わってきます。

最初のうちは「便利な書き方の1つ」くらいの感覚で構いませんが、早めに概念に慣れておくことで、あとから応用が効くようになります。

第一級オブジェクトの条件をやさしく理解する

ここからは、「何ができると第一級オブジェクトと言えるのか」を具体的に見ていきます。

多くの解説では、第一級オブジェクトの条件として次の4つが挙げられます。

  • 変数に代入できる
  • 関数やメソッドの引数に渡せる
  • 関数やメソッドの戻り値として返せる
  • 配列・オブジェクトなどのデータ構造に入れられる

変数に代入できる

第一級オブジェクトは、変数に代入できます。

これは、数値や文字列では当たり前にできていることです。

たとえばJavaScriptでは、次のように書けます。

JavaScript
// 数値を変数に代入
let x = 10;

// 関数を変数に代入
function greet() {
  console.log("Hello");
}
let fn = greet; // 関数をそのまま代入

ここでは、greetという関数をfnという変数に代入しています。

数値10と同じようにgreetを「値」として扱えているので、JavaScriptの関数は第一級オブジェクトといえます。

関数やメソッドの引数に渡せる

第一級オブジェクトは、関数やメソッドの引数として渡すことができます。

JavaScript
function runTwice(fn) {
  fn();
  fn();
}

function hello() {
  console.log("Hello");
}

// 関数 hello を、そのまま値として渡している
runTwice(hello);

ここで渡しているのはhello()の実行結果ではなく、helloという関数そのものです。

数値42や文字列"world"と同じように、「関数」という値を渡せています。

このように、関数の中から別の関数に仕事を任せることができるのが、第一級オブジェクトとしての関数の強みです。

関数やメソッドの戻り値として返せる

第一級オブジェクトは、関数の戻り値としても返すことができます。

JavaScript
function createGreeter(name) {
  return function () {
    console.log("Hello, " + name);
  };
}

const greetAlice = createGreeter("Alice");
greetAlice(); // Hello, Alice

createGreeterは、呼び出されると関数を返す関数です。

数値を返すのと同じように関数を返している、という点がポイントです。

データ構造(配列・オブジェクトなど)に入れられる

最後に、第一級オブジェクトは配列やオブジェクトなどのデータ構造にも入れられます。

JavaScript
const items = [
  1,
  "text",
  function () {
    console.log("I am in array");
  },
];

items[2](); // "I am in array"

このように、数値や文字列と同じ配列の中に、関数も並べて格納できます。

データとして関数をコレクションにまとめることができるのは、関数が第一級オブジェクトだからです。

身近な例で見る第一級オブジェクト

抽象的な説明だけではイメージしにくいので、ここからは実際の言語における第一級オブジェクトの例を見ていきます。

数値や文字列が第一級オブジェクトの例

まずは、どの言語でもほぼ間違いなく第一級オブジェクトである数値と文字列を確認します。

JavaScriptの例で見てみましょう。

JavaScript
// 数値
let a = 1;           // 変数に代入
function plusOne(x) { // 引数に渡す
  return x + 1;      // 戻り値として返す
}
const numbers = [a]; // 配列に入れる

// 文字列
let message = "Hi";         // 変数に代入
function shout(text) {      // 引数に渡す
  return text.toUpperCase();// 戻り値として返す
}
const texts = { msg: message }; // オブジェクトに入れる

ここでは、数値も文字列も、先ほど挙げた4つの条件をすべて満たしています。

第一級オブジェクトの条件を確認するときは、「数値や文字列と同じことができるか?」と比較してみると分かりやすくなります。

JavaScriptの関数が第一級オブジェクトの例

JavaScriptでは、関数は第一級オブジェクトです。

先ほどの条件に当てはめて、まとめて確認してみましょう。

JavaScript
// 1) 変数に代入できる
const fn = function () {
  console.log("hello");
};

// 2) 引数に渡せる
function run(fnArg) {
  fnArg();
}
run(fn);

// 3) 戻り値として返せる
function createLogger() {
  return function (msg) {
    console.log(msg);
  };
}
const log = createLogger();
log("log message");

// 4) 配列・オブジェクトに入れられる
const handlers = {
  onClick: function () {
    console.log("clicked");
  },
  onHover: function () {
    console.log("hovered");
  },
};

handlers.onClick();

このように、関数が「ただの値」として動き回れるのが、JavaScriptにおける第一級オブジェクトとしての関数の特徴です。

Pythonの関数が第一級オブジェクトの例

Pythonでも、関数は第一級オブジェクトです。

JavaScriptと同じ観点で見てみましょう。

Python
# 1) 変数に代入できる
def hello():
    print("hello")

greet = hello  # 関数を変数に代入
greet()

# 2) 引数に渡せる
def run(fn):
    fn()

run(hello)

# 3) 戻り値として返せる
def make_multiplier(n):
    def mul(x):
        return n * x
    return mul

times2 = make_multiplier(2)
print(times2(5))  # 10

# 4) データ構造に入れられる
handlers = [hello, greet, lambda: print("lambda")]
for h in handlers:
    h()

Pythonでも、関数は数値や文字列と同じように、変数に入れたり、リストに入れたり、引数に渡したりできます

そのため、Pythonでも「関数は第一級オブジェクトです」と説明されます。

クラスやオブジェクトが第一級オブジェクトになる場合

ここまで見てきたのは「関数」でしたが、クラスそのものや、オブジェクトのインスタンスが第一級オブジェクトとして扱われる言語も多くあります。

JavaScriptの例を見てみましょう。

JavaScript
class User {
  constructor(name) {
    this.name = name;
  }
}

// クラスを変数に代入
const UserClass = User;

// クラスを引数に渡す
function createWithName(ClassRef, name) {
  return new ClassRef(name);
}

const alice = createWithName(UserClass, "Alice");
console.log(alice.name); // Alice

このコードでは、Userというクラス定義そのものを「値」として扱っています。

クラスを変数に入れたり、引数として渡したりしているという点で、クラスも第一級オブジェクトとして扱われているといえます。

Pythonでも似たようなことが可能です。

Python
class User:
    def __init__(self, name):
        self.name = name

UserClass = User  # クラスを変数に代入

def create_user(cls, name):
    return cls(name)

alice = create_user(UserClass, "Alice")
print(alice.name)  # Alice

多くのオブジェクト指向言語では、クラスやオブジェクトも、他の値と同じように扱える「第一級オブジェクト」になっています。

関数が第一級オブジェクトだと何がうれしいか

ここまでで、第一級オブジェクトの条件や、関数が第一級オブジェクトとして扱われる具体例を見てきました。

では、関数が第一級オブジェクトであることによって、実際にどんな良いことがあるのでしょうか。

コールバック関数とイベント処理の理解につながる

JavaScriptで頻出するコールバック関数は、「関数を引数として渡す」という第一級オブジェクトの性質に依存しています。

JavaScript
function doAsyncTask(callback) {
  setTimeout(() => {
    console.log("task done");
    callback(); // 終わったらコールバックを実行
  }, 1000);
}

function afterTask() {
  console.log("after task");
}

doAsyncTask(afterTask);

ここでは、afterTaskという関数をdoAsyncTask「値として渡している」からこそ、処理が終わったタイミングで好きな処理を実行できます。

DOM操作やイベント処理でも同じです。

JavaScript
button.addEventListener("click", function () {
  console.log("button clicked");
});

ここでも、addEventListenerに、「クリックされたときに実行してほしい処理」そのものを値として渡しています

関数が第一級オブジェクトでなければ、このような柔軟な書き方はできません。

高階関数(mapやfilter)を直感的に理解できる

高階関数(higher-order function)とは、「関数を引数に取ったり、関数を戻り値として返したりする関数」のことです。

ここまで読んだ方なら分かるとおり、まさに第一級オブジェクトとしての関数が前提になっています。

代表的な例として、Array.prototype.mapを見てみましょう。

JavaScript
const numbers = [1, 2, 3];

const doubled = numbers.map(function (n) {
  return n * 2;
});

console.log(doubled); // [2, 4, 6]

mapは、「各要素をどう変換するか」という処理を関数として受け取ることで、同じ処理を配列の全要素に一括で適用します。

Pythonのmapでも同様です。

Python
numbers = [1, 2, 3]

def double(n):
    return n * 2

doubled = list(map(double, numbers))
print(doubled)  # [2, 4, 6]

関数を値として扱えるからこそ、「どう処理するか」をデータとして外から差し込めるわけです。

これが理解できると、filterreduceなど、ほかの高階関数も自然に受け入れやすくなります。

初心者がつまずきやすいポイントと意識すべきところ

最後に、初心者が第一級オブジェクトとしての関数でつまずきやすいポイントと、そのときに意識するとよいことを整理します。

1つ目は、「関数そのもの」と「関数の実行結果」の区別です。

JavaScript
run(hello);  // 関数そのものを渡す
run(hello()); // hello() の実行結果を渡してしまう (多くの場合、意図と違う)

hello関数そのものhello()関数を実行した結果です。

第一級オブジェクトとして扱いたいときは「丸括弧を付けない」ことを意識すると良いでしょう。

2つ目は、「関数も値である」という発想に慣れることです。

最初のうちは「関数は“命令のかたまり”であって、データではない」と感じてしまいがちです。

しかし、第一級オブジェクトという観点では、関数も数値や文字列と同じく「動き回れるデータ」だと捉えます。

3つ目は、「数値や文字列で当たり前にできることが、関数にもできるか?」をチェックする癖です。

  • 変数に代入できるか
  • 引数に渡せるか
  • 戻り値として返せるか
  • 配列やオブジェクトに入れられるか

これらを意識してコードを読むと、「この言語では何が第一級オブジェクトなのか」が徐々に見えてきます。

まとめ

この記事では、第一級オブジェクト(first-class citizen)とは何かについて、次の流れで解説しました。

まず、第一級オブジェクトとは「その言語の中で、他の値と同じように自由に扱えるもの」であり、「値として扱える」ことがキーワードであると説明しました。

その条件として、変数に代入できる、引数に渡せる、戻り値として返せる、配列やオブジェクトに入れられる、という4つを紹介しました。

次に、数値や文字列、JavaScriptやPythonにおける関数、そしてクラスといった身近な例を通じて、実際にどのように第一級オブジェクトが使われているかを見てきました。

最後に、関数が第一級オブジェクトであることのメリットとして、コールバック関数やイベント処理、高階関数(mapやfilter)の理解が進むこと、そして初心者がつまずきやすいポイントとして「関数そのもの」と「関数の実行結果」の違いに注意する必要があることを確認しました。

これからコールバックや高階関数、関数型プログラミングといったトピックを学んでいくときには、ぜひ「関数も数値や文字列と同じ“値”として動き回れる第一級オブジェクトだ」というイメージを思い出してみてください。

抽象的だった説明が、少しずつ具体的なコードと結びついて見えるようになっていくはずです。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!