MENU

JavaScript構文オブジェクト

【JavaScript】 new演算子は何をやっている?

更新日:2020/10/22

 

一時期、オブジェクト作成はnewが必要ないという議論がありました。
確かに必要ありませんが、newの本質は単なるオブジェクト作成ではありません。

 

そこで今回は、new演算子が何をやっているのかについて解説します。

 

new演算子は継承の仕組みを構築している

 

new演算子は、コンストラクター関数のprotorypeプロパティを、新規オブジェクトのプロトタイプチェーンに組み込む処理をおこなっています。
プロトタイプチェーンは、JavaScript上での継承の仕組みです。

 

参考記事:
【JavaScript】 プロトタイプとは?prototypeプロパティはプロトタイプではない件について

 

 

newが必要ないケース

 

コンストラクター関数のprototypeプロパティに関数独自のプロパティが用意されていない場合は、newを使用しなくても問題ありません。

 

例:

 

newを使用するパターン

 


function a( x ){
  this.x = x;
}
const b = new a( 10 );

 

これを、newをしないパターンに置き換えてみます。

 

newを使用しないるパターン

 


function a( x ){
  /* const obj = {}; obj.x = x; return obj; */
  return { x: x }; // 上コメントの短縮パターン
}
const b =  a( 10 );

 

newが必要なケース

コンストラクター関数のprototypeプロパティに関数独自のプロパティが用意されている場合は、newが使用です。

 

newでオブジェクトインスタンスを生成

 


function a( x ){
    this.x = x;
}
a.prototype={
   getX:function(){ return this.x }
};
const b = new a( 10 );
const c =  b.getX();  // c = 10

 

上の関数aをnewを、newが必要ないケースで例示したパターンに書き換えてみます。

 

newを使用しないパターンに置き換え

 


function a( x ){
    return { x: x };
}
a.prototype={
   getX:function(){ return this.x }
};
const b =  a( 10 );
const c =  b.getX();  // TypeError: b.getX is not a function

 

a.prototypeが、関数aで返されたオブジェクトのプロタイプチェーンに組み込まれていないため、b.getX() を実行できません。

 

ただし、次のように Object.create() を使用すると、プロタイプチェーンを構築することができます。

 

newを使用しないで、プロタイプチェーンを構築する

 


function a( x ){
        const obj = Object.create(a.prototype);
        obj.x = x;
        return obj;
}
a.prototype={
        getX:function(){ return this.x }
};
const b =  a( 10 );
const c =  b.getX();  // c = 10

 

newを使用したほうが簡潔なので、この方法はおススメできません。

newがやっていること

 

new演算子は、次のことをおこなっています。

 

関数内コード実行前

 

  1. オブジェクトとして最低限の機能を持っている、新規オブジェクトを作成。

     

    新規オブジェクト:{ }

     

  2. 新規オブジェクトのプロパティチェーンに、コンストラクター関数のprototypeプロパティへの参照をセット

     

    新規オブジェクト:{
       [[プロパティチェーン]] → コンストラクター関数のprototypeプロパティ
    }

     

  3. 新規オブジェクトを this として、関数内コードに渡す

 

関数内コード終了後

 

関数内コードにreturn式がない場合、this値をリターンします。

 

例えば、次のように最後にthis値をリターンするコードがあるとき、

 

this値をリターン

 


function a( x ){
    this.x = x;
    return this;
}

 

最後のreturn行を削除できます。

 

this値のリターンを省略

 


function a( x ){
    this.x = x;
}

 

これは、new演算子の記述漏れ時に、不具合を発見するのに役立ちます。

 

newの付け忘れ

 


function a( x ){
    this.x = x;
}
const b = a( 10 );  // b は undefined
const c = b.x;       // TypeError: b is undefined

 

new演算子がない場合、関数aからの返り値はundefinedです。
そのため、後に続くコードでプロパティを参照しようとするとエラーとなり、処理がストップします。

 

this値をリターンした場合、そのまま処理が続く可能性があり、潜在的な不具合となるかもしれません。

newあるなしでの、関数内 thisの値

 

関数を new演算子で呼び出した場合、関数内のthisは新規オブジェクトです。
このオブジェクトは、自由にプロパティを追加しても問題ありません。

 

しかしnew演算子を使用しない場合、不具合が生じることがあります。
この場合のthis値は、strictモードかどうかで変わってきます。

 

strictモードの場合、this値は undefined です。
undefinedにプロパティを追加すると、エラーが発生します。
デバッグ時にエラーを捕捉できるようにしておけば、比較的容易に修正可能です。

 

非strictモードの場合、this値はブラウザならWindowsです。
つまり、this値に追加したつもりのプロパティが、グローバルオブジェクトに追加されたことになります。
これは、値の競合などがおき、気が付きにくい不具合の原因となります。

 

 

大きなプロジェクトなどでは、次のような方法で new呼び出しの判定をおこない、エラーをスローするなどの方策をするのもよいですね。

 

new呼び出し以外は、エラーをスロー

 


function a( x ){
        if( new.target === undefined ) throw new Error("newで呼び出してください");
       this.x = x;
}

まとめ

 

new演算子はオブジェクトを作成するだけではなく、継承の仕組みを構築しています。
とても重要な演算子なんです。

 

また、JavaScript初心者のうちはnew演算子を使用したらエラーがでる、ということも多いです。
そんなときは、次の記事を参考にしてください。
【JavaScript】 new したら コンストラクターではないと言われたなぜ?

 

そもそもコンストラクターって何?という人は、次の記事が参考になります。
【JavaScript】 コンストラクターとは?関数とは違うのか?

記事の内容について

 

こんにちはけーちゃんです。
説明するのって難しいですね。


「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。

裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。

そんなときは、ご意見もらえたら嬉しいです。

ご意見はこちら。
https://affi-sapo-sv.com/info.php

【お願い】

お願い

■このページのURL


■このページのタイトル


■リンクタグ