【俺的理解】JavaScriptのnew演算子

公開日: 

参考記事

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/new

https://ja.javascript.info/constructor-new

はじめに

JavaScriptnew 演算子とはなんですか?と自分で自分に問いかけて、説明できなかったので調べてまとめました。

通常のオブジェクト

const user = {
  name: 'Jack',
  isAdmin: false,
};

通常のオブジェクトは上のように作成できます。しかし、複数のユーザーやメニューのアイテムなど似たようなオブジェクトを複数作成する必要がある場合があったとしましょう。その場合、上のような記法で繰り返しオブジェクトを作成しようとするとめんどくさいし、どうしてもミスが発生しやすくなってしまいます。そこで登場するのが

  • new 演算子
  • コンストラクタ関数

です。こいつらを利用することで似たようなオブジェクトを簡単に作成することができるようになります。

new 演算子・コンストラクタ関数とは

まずはコンストラクタ関数から

コンストラクタ関数とは

コンストラクタ関数と呼ばれる関数は基本的には通常の関数と全く同じです。しかし以下の慣習があります。

  • 最初の文字は大文字
  • new 演算子のみで実行されるべき

慣習というのはコードを読みやすくするための暗黙の了解的なものだと自分は理解していて、

boolean 型の変数名は isHoge みたいな形にした方がわかりやすい

みたいな感じだと思ってます。

new 演算子とは

sample.js
// コンストラクタ関数
function User(name) {
  this.name = name;
  this.isAdmin = false;
}

// new演算子を用いてコンストラクタ関数を実行
let user = new User('Jack');

alert(user.name); // Jack
alert(user.isAdmin); // false

new 演算子を用いてコンストラクタ関数が実行された場合、以下の処理が行われます。

  1. 新しい空のオブジェクトが作成され、 this  に割り当てられる。
  2. 関数本体を実行します。通常は新しいプロパティを追加することで  this  に変更を加えます。
  3. this  の値が返されます。

つまり上の例で見ると、new 演算子で関数を実行したことにより、以下の処理が行われていることになります。

function User(name) {
  // this = {};  (暗黙)

  // this へプロパティを追加
  this.name = name;
  this.isAdmin = false;

  // return this;  (暗黙)
}

したがって上の例の

let user = new User('Jack');

let user = {
  name: 'Jack',
  isAdmin: false,
};

と同じ意味になります。似たオブジェクトを複数作成するときに new 演算子とコンストラクタ関数が便利という意味がわかったような気がします。

ここまで new 演算子とコンストラクタ関数について調べましたが、まとめると

new 演算子で実行されることを期待されている関数のことをコンストラクタ関数とよび、慣習的に最初の文字は大文字であるべき

ってことになるでしょうか

メソッドも this に追加可能

余談ですが、new 演算子を使った時にメソッドもプロパティとして追加できます。

// コンストラクタ関数
function User(name) {
  this.name = name;

  this.sayHi = function () {
    alert('My name is: ' + this.name);
  };
}

let john = new User('John');

john.sayHi(); // My name is: John

コンストラクタ関数の戻り値

コンストラクタ関数の役割は必要なものを this の中に書き込み、this を return することなので、コンストラクタ関数は通常 return 文を持ちません。

だた、return が定義されていた場合は以下のルールに従って値を返します

  • オブジェクトが return された場合はそのオブジェクトを返す
  • プリミティブ値が return されたときは無視する

これは最後に試してみます。

new 演算子を使ってみる

普通のコンストラクタ関数

function Hoge() {
  this.hoge = 'hoge';
  this.fuga = 2;
}

const piyo = new Hoge();

console.log(piyo.hoge); // 'hoge'
console.log(piyo.fuga); // 2

よし。

小文字で始まっていても new 演算子使える

function hoge() {
  this.hoge = 'hoge';
  this.fuga = 2;
}

const piyo = new hoge();

console.log(piyo.hoge); // 'hoge'
console.log(piyo.fuga); // 2

小文字はじまりでも全然使えるが、わかりにくいので暗黙的に NG

メソッド追加してみる

function Hoge() {
  this.hoge = 'hoge';
  this.fuga = 2;
  this.sayPiyo = function () {
    return 'piyopiyo' + this.hoge;
  };
}

const piyo = new Hoge();

console.log(piyo.hoge); // 'hoge'
console.log(piyo.fuga); // 2
console.log(piyo.sayPiyo()); // piyopiyohoge

メソッド追加できる。

特殊な return をつけてみる

function Hoge() {
  this.hoge = 'hoge';
  this.fuga = 2;

  return { hoge: 'hogehoge' };
}

const piyo = new Hoge();

console.log(piyo.hoge); // 'hogehoge'
console.log(piyo.fuga); // undefined

オブジェクトを返したらそのオブジェクトが返ってきた。

function Hoge() {
  this.hoge = 'hoge';
  this.fuga = 2;

  return 7;
}

const piyo = new Hoge();

console.log(piyo.hoge); // 'hoge'
console.log(piyo.fuga); // 2

プリミティブ値を返したらガン無視で this が返ってきた。

最後に

new ってクラスをインスタンス化するときのアレでしょ的な感じだったのを理解できたのが嬉しい。実際調べてみたらちょっと違ったし。

では

Bye