■ 概要
javascriptにおける new 呼び出し(以下:コンストラクタ呼び出し)を理解するために、関数呼び出しとの差異をサンプルコードを踏まえてまとめる。
■ サンプルコード
定義された Sam関数 を対象に、コンストラクタ呼び出しした場合と関数呼び出しした場合の差異を検証するサンプルコード。
function Sam(num,string){
//↓Line②
this.num = num;
//↓Line③
this.string = string;
}
//↓Line④
Sam.prototype.getState = function(){
console.log('num: '+this.num+', string: '+this.string);
}
//↓Line①
var constSam1 = new Sam(1,'いち');
//↓Line⑤
constSam1.string = '壱';
constSam1.getState();
//Log① consoleに num: 1, string: 壱 のlog出力
//↓Line⑥
var constSam2 = new Sam(2,'に');
constSam2.getState();
//Log② consoleに num: 2, string: に のlog出力
//↓Line⑦
var funcSam = Sam(3,'さん');
console.log('num: '+window.num+', string: '+window.string);
//Log③ consoleに num: 3, string: さん のlog出力
//↓Line⑧
funcSam.string = 5;
//Log④ funcSam.string undefinedのエラー
//↓Line⑨
funcSam.getState();
//Log⑤ funcSam.getState undefinedのエラー
■ サンプルコードを使ったコンストラクタ呼び出しの説明
コンストラクタ呼び出しと関数呼び出しの違いについて、理解しなければいけない点は以下の2点だと思われる。
1, this結合
2, prototypeオブジェクト
◇コンストラクタ呼び出しの仕様
関数に new をつけた形で呼び出すと、コンストラクタ呼び出しとなる。
コンストラクタ呼び出しと関数呼び出しでは、下記の3点の違いが見込まれる。
Ⅰ, コンストラクタ呼び出しした場合、新しいオブジェクトとして this が生成される
Ⅱ, コンストラクタ呼び出しによって作成された新しいオブジェクト this は、関数に定義されたprototypeを継承する
Ⅲ, コンストラクタ呼び出しされた関数は、作成された新しいオブジェクト this を返却する
以下、サンプルコードを追って、上記を証明する。
◇説明
Line①の行で Sam関数
がコンストラクタ呼び出しされている。
この時、Sam関数
内では新しいオブジェクト this
が生成され、Line②・③の行でこのオブジェクト this
に引数 1
いち
を格納している。
さらにこの this
はコンストラクタ呼び出しによって生成されたのでLine④で定義されている Sam関数
の prototype
を継承している。
Sam関数
はコンストラクタ呼び出しされたので、生成したオブジェクト this
を返却している。
したがってLine①の var constSam1
は、引数 1
いち
が格納され Sam関数
の prototype
が継承されたオブジェクト this
を参照している。
Line⑤の constSam1.string
はすなわち 'this.string' であるといえるので、格納した 壱
はもともとLine③で格納されていた いち
を上書きしている。
ーーーー ここまでの過程を経て Log① が出力されることによって Ⅰ Ⅱ Ⅲ が証明される。
Line⑥にて、新たに Sam関数
をコンストラクタ呼び出ししている。
この時、Sam関数
ではLine①で生成されたのとは別の新しいオブジェクト this
を生成し、返却している。
ーーーー Log②が出力されることによって Ⅰ がより確実に証明される。
Line⑦の行で Sam関数
が関数呼び出しされている。
関数呼び出しされた時には、新しいオブジェクトは生成されない。
したがって Sam関数
内の this
はスコープチェーンを辿る事になる。
このサンプルコードの場合、this
をどこにも定義していないので this
は window
を参照する事になる。(ブラウザの場合)
ーーーー Log③が出力されることによって上記が証明される。
関数呼び出しされた時には this
は生成されないし返却もしないので、Line⑧のような呼び出しをしてもLog④の様にエラーが出る。
また、関数呼び出しされた時には this
は生成されないし関数の prototype
も継承されないのでLine⑨のような呼び出しをしてもLog⑤の様にエラーが出る。
ーーーー 上記は Ⅰ をより確実に証明している。