お知らせ:2021/2/18 ツールサイト(affi-sapo-sv.com)から、開発ノートを独立させました。
【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演算子は、次のことをおこなっています。
関数内コード実行前
- オブジェクトとして最低限の機能を持っている、新規オブジェクトを作成。
新規オブジェクト:{ }
- 新規オブジェクトのプロパティチェーンに、コンストラクター関数のprototypeプロパティへの参照をセット
新規オブジェクト:{
[[プロパティチェーン]] → コンストラクター関数のprototypeプロパティ
} - 新規オブジェクトを 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://note.affi-sapo-sv.com/info.php
【お願い】

■このページのURL
■このページのタイトル
■リンクタグ