JS: new 呼び出しについて理解する

More than 3 years have passed since last update.


■ 概要

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 をどこにも定義していないので thiswindow を参照する事になる。(ブラウザの場合)

ーーーー Log③が出力されることによって上記が証明される。

関数呼び出しされた時には this は生成されないし返却もしないので、Line⑧のような呼び出しをしてもLog④の様にエラーが出る。

また、関数呼び出しされた時には this は生成されないし関数の prototype も継承されないのでLine⑨のような呼び出しをしてもLog⑤の様にエラーが出る。

ーーーー 上記は Ⅰ をより確実に証明している。