IORI online School

JavaScript、html、css の無料学習サイト

【JavaScript 上級講座】thisのまとめ(5つの例題でthisを完全制覇)

[JavaScript 上級講座]thisのまとめ(5つの例題でthisを完全制覇)

JavaScriptのthisキーワードを学習する。 thisの定義は簡単である。

this プログラムを実行した時のオブジェクトである。

thisは、プログラムを実行した時のオブジェクトを意味する。 thisの定義は、かくの如く簡単である。 それにもかかわらず、thisは多くの問題を提起する。

thisに関わる多くの問題は、「プログラムを実行した時」という部分から発生する。 thisが意味するオブジェクトは、 プログラムを記述した時のオブジェクトではない。

プログラムを記述した時、「thisはこのオブジェクトを意味する」と思っていたが、 いざプログラムを実行すると、オブジェクトが変化していて、 「thisが意味するオブジェクトが想定外だった」という場面が多々有る。

本講座では多種多様のプログラムを見ながら、thisに慣れていく。

thisの基礎

001<script>
002//display()関数を定義
003function display () {
004
005  //thisを表示
006  alert ( this ) ;
007}
008//[window]
009display () ;
010</script>

プログラムを実行すると「window」と表示する。

3行目でdisplay()関数を定義する。オブジェクトの中に関数を定義しない場合、 自動的にwindowオブジェクト(グローバルオブジェクト)のプロパティになる。 さて、9行目でdisplay()関数を実行する。 display()関数が実行すると、6行目が実行する。

「this」が存在する。このthisは何を意味するだろうか?

this プログラムを実行した時のオブジェクトである。

いま、windowオブジェクトの中でdisplay()関数を実行している。 つまり、thisはwindowオブジェクトを意味する。 プログラムを実行すると「window」と表示する。

このような感じでサンプルプログラムを見る。最初の方は簡単なthisである。

001<script>
002//ioriオブジェクト
003var iori = {
004  x : "IORI" ,
005  display : function () {
006    alert ( this.x ) ;
007  }
008}
009//[IORI]
010iori.display () ;
011</script>

プログラムを実行すると「IORI」と表示する。

3行目で変数ioriを宣言して、オブジェクトを参照する。 オブジェクトの内容は、後ほど見る。 10行目で変数ioriが参照するオブジェクトのdisplay()関数を実行する。

003var iori = {
004  x : "IORI" ,
005  display : function () {
006    alert ( this.x ) ;
007  }
008}

5行目のdisplay()関数が実行する。 6行目にthisがある。このthisは何を意味するだろうか?

this プログラムを実行した時のオブジェクトである。

いま、ioriが参照するオブジェクトに対してdisplay()関数を実行した。 つまり、実行中のオブジェクトは「ioriが参照するオブジェクト」である。 6行目のthisは、「ioriが参照するオブジェクト」を意味する。 オブジェクトのxプロパティの値は文字列「IORI」である。 ダイアログに「IORI」と表示する。解説は以上である。

基礎的thisの最後のサンプルプログラムである。

001<script>
002//Ioriコンストラクタ関数
003var Iori = function ( x ) {
004  this.x = x ;
005}
006//display()関数を定義
007Iori.prototype.display = function () {
008    alert ( this.x ) ;
009}
010//Iori型オブジェクト
011var iori = new Iori ( "IORI" ) ;
012
013//[IORI]
014iori.display () ;
015</script>

プログラムを実行すると「IORI」と表示する。

3行目でIoriコンストラクタ関数を定義する。 7行目でIoriコンストラクタ関数のprototypeオブジェクトにdisplay()関数を定義する。 11行目でIoriコンストラクタ関数からオブジェクトを生成して、 変数ioriへ代入する。14行目で変数ioriが参照するオブジェクトに対して、 display()関数を実行する。

002//Ioriコンストラクタ関数
003var Iori = function ( x ) {
004  this.x = x ;
005}
006//display()関数を定義
007Iori.prototype.display = function () {
008    alert ( this.x ) ;
009}

7行目のdisplay()関数が実行する。8行目にthisがある。 ・・・これは難しい。図解する。

オブジェクト Iori
変数
iori
x: "IORI"

__proto__ : {

  【参照X】

}
prototype : {

  【参照X】

  display : function

  __proto__ : {

    【参照Y】

  }
}

変数ioriが参照するオブジェクトは、Ioriコンストラクタ関数から生成されたため、 xプロパティを持つ。 こんかい、オブジェクトのxプロパティに 文字列「IORI」が入っている。関数は存在しない。

この状態で、オブジェクトに対してdisplay()関数を実行した。 オブジェクトにdisplay()関数は存在しない。 その場合、プロトタイプチェーンをさかのぼる。 Ioriコンストラクタ関数のprototypeオブジェクトにdisplay()関数が存在する。 このdisplay()関数が実行する。 さて、display()関数の中でthisが利用されていた。 いま、動いているオブジェクトは、変数ioriが参照するオブジェクトである。

007Iori.prototype.display = function () {
008    alert ( this.x ) ;
009}

thisは実行中のオブジェクトである。つまりioriオブジェクトである。 8行目を実行すると、つぎのような状態になる。

007Iori.prototype.display = function () {
008    alert ( { x : "IORI" } .x ) ;
009}

プログラムを実行すると、 ダイアログに「IORI」と表示する。 解説は以上である。

ここまでが基礎的サンプルプログラムである。

関数が持つ関数、call()関数を実行する

001<script>
002//window.getX()関数
003function getX () {
004  alert ( this.x ) ;
005}
006//window.xプロパティ
007var x = "ERROR" ;
008
009//ioriオブジェクト
010var iori = {
011  x : "IORI"
012}
013//[ERROR]
014window.getX.call ( window ) ;
015</script>

プログラムを実行すると「ERROR」と表示する。

3行目でgetX()関数を定義する。getX()関数はグローバルスコープで定義しているので、 windowオブジェクトの関数になる。 7行目で変数xを定義して文字列「ERROR」を代入する。 変数xもwindowオブジェクトのプロパティになる。 10行目から12行目でオブジェクトを定義する。 こんかい、このプログラムは意味がないので気にしないでほしい。

14行目で、・・・14行目は何をしているのかな?

関数.call ( [オブジェクト] ) オブジェクトに対して、関数を実行する。

まず注意したいのが、まず関数が存在する。 そして、関数の中のcall()関数を実行する。 実は、関数自身もオブジェクトである。 そして 関数の中に、様々な関数が存在する。 call()関数も、関数内に存在する関数(メソッド)の1つである。

関数.call ( [オブジェクト] ) オブジェクトに対して、関数を実行する。

引数にオブジェクトを渡してcall()関数を実行すると、 オブジェクトに対して「関数」が実行する。

001<script>
002//window.getX()関数
003function getX () {
004  alert ( this.x ) ;
005}
006//window.xプロパティ
007var x = "ERROR" ;
008
009//ioriオブジェクト
010var iori = {
011  x : "IORI"
012}
013//[ERROR]
014window.getX.call ( window ) ;
015</script>

14行目で、call()関数を実行する。call()関数の引数に、windowオブジェクトを渡す。 つまり14行目は、 windowオブジェクトに対して、getX()関数を実行する プログラムである。

3行目でgetX()関数が定義されている。14行目が実行すると、 この関数が呼ばれる。4行目のthisは何を意味するだろうか? 今、windowオブジェクトに対してgetX()関数を実行した。 つまり、thisはwindowオブジェクトを意味する。 windowオブジェクトのxプロパティは、7行目の文字列「ERROR」である。 4行目が実行すると、ダイアログに「ERROR」と表示する。 解説は以上である。

次のプログラムで、call()関数の挙動を確認する。

001<script>
002//window.getX()関数
003function getX () {
004  alert ( this.x ) ;
005}
006//window.xプロパティ
007var x = "ERROR" ;
008
009//ioriオブジェクト
010var iori = {
011  x : "IORI"
012}
013//[IORI]
014window.getX.call ( iori ) ;
015</script>

プログラムを実行すると「IORI」と表示する。

不思議なプログラムである。前回との違いは、14行目である。 14行目でcall()関数を実行する。 call()関数は、getX()関数を実行する関数である。 今回、call()関数の引数に変数ioriが参照するオブジェクトを渡す。 call()関数が実行すると、変数ioriが参照するオブジェクトに対して、 getX()関数が実行する。変数ioriが参照するオブジェクトは、 getX()関数を持っていない。という疑問が高速で飛んでくる。

もう一度おさらいする。いまwindowオブジェクトのgetX()関数を、 ioriオブジェクトに対して実行する。 実行する関数は、window.getX()関数である。 「window.getX()関数は、どのオブジェクトの中に存在するか?」という問いは、 存在しない。存在しない。window.getX()関数が動く。

003function getX () {
004  alert ( this.x ) ;
005}
006//window.xプロパティ
007var x = "ERROR" ;
008
009//ioriオブジェクト
010var iori = {
011  x : "IORI"
012}

3行目が動く。4行目のthisは何を意味するだろうか? getX()関数はwindowオブジェクトの関数である。 では、thisはwindowオブジェクトだろうか? windowオブジェクトのxプロパティがダイアログに表示するだろうか?

this プログラムを実行した時のオブジェクトである。

いま、window.getX()関数は変数ioriが参照するオブジェクトに対して動作している。 thisはwindowオブジェクトの中に存在するが、 ここのthisは変数ioriが参照するオブジェクトである。

003function getX () {
004  alert ( { x : "IORI" }.x ) ;
005}
006//window.xプロパティ
007var x = "ERROR" ;
008
009//ioriオブジェクト
010var iori = {
011  x : "IORI"
012}

thisをオブジェクトへ切り替えた。プログラムが実行すると「IORI」とダイアログに表示する。 解説は以上である。

関数というものは、 オブジェクトの中に定義するため、 「関数はオブジェクトとセット」と見なしがちである。 あるいは「関数はオブジェクトの中のプロパティと連携する」と考えがちである。 それは普通の考え方であるし、そうありたいものである。

しかし JavaScriptでは、関数は独立して存在する。 「独立した関数を、どのオブジェクトに対して実行するか?」という点が JavaScriptでは重要である。 実行中のオブジェクトがthisである。

「関数は独立したモノ」という認識を明確にするため、 もう一つサンプルプログラムを用意した。

001<script>
002//itemオブジェクト
003var item = {
004  x : "item" ,
005  getX : function () {
006      alert ( this.x ) ;
007  }
008} ;
009//window.xプロパティ
010var x = "ERROR" ;
011
012//IORIオブジェクト
013var iori = {
014  x : "IORI"
015}
016//[ERROR]
017item.getX.call ( window ) ;
018
019//[IORI]
020item.getX.call ( iori ) ;
021</script>

プログラムを実行すると「ERROR」、「IORI」と表示する。

解説する。3行目で変数itemを宣言してオブジェクトを代入する。 オブジェクトの中を見る。

002//itemオブジェクト
003var item = {
004  x : "item" ,
005  getX : function () {
006      alert ( this.x ) ;
007  }
008} ;

itemオブジェクトの中にxプロパティとgetX()関数が存在する。 getX()関数の処理を見る。 6行目で、xプロパティの値をダイアログに表示する。 ここのthisは何を意味するだろうか? itemオブジェクトだろうか? もし、thisがitemオブジェクトならば、 getX()関数を実行すると、ダイアログに「item」と表示する。

this プログラムを実行した時のオブジェクトである。

thisは、(別段の処理をしない限り) プログラムを実行した時に決定する。 いまは、itemオブジェクトを意味しているように見えるが、 プログラムを実行するまで分からない。

009//window.xプロパティ
010var x = "ERROR" ;
011
012//IORIオブジェクト
013var iori = {
014  x : "IORI"
015}
016//[ERROR]
017item.getX.call ( window ) ;
018
019//[IORI]
020item.getX.call ( iori ) ;

解説を続ける。10行目で変数xへ文字列「ERROR」を代入する。 変数xはグローバルスコープで定義しているのでwindowオブジェクトのプロパティになる。 13行目でオブジェクトを定義して、変数ioriへ代入する。 変数ioriが参照するオブジェクトには、xプロパティが存在する。

さて、17行目でcall()関数を実行する。 call()関数の引数にwindowオブジェクトを渡す。 つまり、windowオブジェクトに対してitem.getX()関数を実行する。 実行するオブジェクトはwindowオブジェクトである。

002//itemオブジェクト
003var item = {
004  x : "item" ,
005  getX : function () {
006      alert ( this.x ) ;
007  }
008} ;

item.getX()関数が実行すると、6行目が動く。 6行目のthisは、今動いているオブジェクトである。 今動いているオブジェクトはwindowオブジェクトである。 itemオブジェクトはgetX()関数を保持するオブジェクトである。 動いているオブジェクトではない。 6行目のプログラムが実行すると、windowオブジェクトのxプロパティの値「ERROR」が ダイアログに表示する。

012//IORIオブジェクト
013var iori = {
014  x : "IORI"
015}
016//[ERROR]
017item.getX.call ( window ) ;
018
019//[IORI]
020item.getX.call ( iori ) ;

20行目で、call()関数を実行する。 call()関数の引数に、変数ioriが参照するオブジェクトを渡す。 つまり、変数ioriが参照するオブジェクトに対して、 itemオブジェクトのgetX()関数を実行する。

003var item = {
004  x : "item" ,
005  getX : function () {
006      alert ( this.x ) ;
007  }
008} ;
009//window.xプロパティ
010var x = "ERROR" ;
011
012//IORIオブジェクト
013var iori = {
014  x : "IORI"
015}

5行目のgetX()関数が実行すると、6行目が動作する。 6行目のthisは何か?現在、ioriオブジェクトに対してgetX()関数が実行している。 つまり、thisはioriが参照するオブジェクトである。 プログラムを実行すると、 ioriオブジェクトのxプロパティの値「IORI」がダイアログに表示する。

これがJavaScriptである。

thisとインナー関数とクロージャ

thisを理解するために学習用のプログラムを掲載する。 今後、利用しなくなるプログラムかもしれない。 しかし、古代のプログラムをメンテナンスする場合、 こんかいのプログラムが役立つこともあるだろう。

001<script>
002//ioriオブジェクト
003var iori = {
004  x : "IORI" ,
005  
006  //関数を戻す
007  factory : function () {
008  
009    return function () {
010      return this.x ;
011    }
012  }
013}
014//factory()関数を実行して
015//関数を受け取る
016var f = iori.factory () ;
017
018//[undefined]
019alert ( f () );
020</script>

プログラムを実行すると「undefined」と表示する。

16行目から解説する。16行目でioriオブジェクトのfactory()関数を実行して、 戻り値を変数fで受け取る。 では、factory()関数を見る。

007  factory : function () {
008  
009    return function () {
010      return this.x ;
011    }
012  }

factory()関数の処理は、9行目だけである。 9行目でreturnキーワードの後ろに戻り値を記述する。 戻り値は関数である。 factory()関数を実行すると、9行目から11行目までの関数が戻る。

001<script>
002//ioriオブジェクト
003var iori = {
004  x : "IORI" ,
005  
006  //関数を戻す
007  factory : function () {
008  
009    return function () {
010      return this.x ;
011    }
012  }
013}
014//factory()関数を実行して
015//関数を受け取る
016var f = iori.factory () ;
017
018//[undefined]
019alert ( f () );
020</script>

いま、16行目を解説していた。16行目でfactory()関数を実行すると、 戻り値として9行目の関数が戻る。

002//factory()関数を実行して
003//関数を受け取る
004var f = function () {
005      return this.x ;
006    }
007
008//[undefined]
009alert ( f () );

変数fに代入する関数を、このように記述できる。 さて、プログラムの最後で、変数fに代入された関数を実行する。

002//ioriオブジェクト
003var iori = {
004  x : "IORI" ,
005  
006  //関数を戻す
007  factory : function () {
008  
009    return function () {
010      return this.x ;
011    }
012  }
013}

ここで9行目の関数が実行する。10行目にthisがある。 このthisはなんだろうか?一見ioriオブジェクトのような気がする。 しかし、プログラムをもう一度見直す。

014//factory()関数を実行して
015//関数を受け取る
016var f = iori.factory () ;
017
018//[undefined]
019alert ( f () );

変数fはグローバルスコープで宣言しているので、windowオブジェクトのプロパティである。 つまり、プログラムは次のように記述できる。

014//factory()関数を実行して
015//関数を受け取る
016window.f = iori.factory () ;
017
018//[undefined]
019alert ( window.f () );

このプログラムを見ると、windowオブジェクトに対して関数f()を実行している。

002//ioriオブジェクト
003var iori = {
004  x : "IORI" ,
005  
006  //関数を戻す
007  factory : function () {
008  
009    return function () {
010      return this.x ;
011    }
012  }
013}

関数f()は9行目から11行目の関数である。 10行目のthisは、windowオブジェクトを意味する。 こんかいwindowオブジェクトにxプロパティを作成していないので、 プログラムを実行すると「undefined」と表示する。 グローバルスコープに変数xを宣言して値を代入したなら、 その値が表示する。

001<script>
002//ioriオブジェクト
003var iori = {
004  x : "IORI" ,
005  
006  //関数を戻す
007  factory : function () {
008  
009    return function () {
010      return this.x ;
011    }
012  }
013}
014var x = "ERROR" ;
015
016//factory()関数を実行して
017//関数を受け取る
018var f = iori.factory () ;
019
020//[ERROR]
021alert ( f () );
022</script>

プログラムを実行すると「ERROR」と表示する。

14行目でwindowオブジェクトにxプロパティを追加した。 21行目を実行すると、 windowオブジェクトのxプロパティの値「ERROR」がダイアログに表示する。 解説は以上である。

こんかい、プログラムを記述した時、 プログラマーの頭の中では、10行目のthisはioriオブジェクトを意味してほしかったかもしれない。

そうに違いない。そうかもしれない。

プログラムを改善する。 10行目を実行した時に、xプロパティの文字列「IORI」を 戻り値にする方法を見る。

001<script>
002//ioriオブジェクト
003var iori = {
004  x : "IORI" ,
005  
006  //関数を戻す
007  factory : function () {
008  
009    //クロージャ
010    var that = this ;
011    return function () {
012      return that.x ;
013    }
014  }
015}
016//factory()関数を実行して
017//関数を受け取る
018var f = iori.factory () ;
019
020//[IORI]
021alert ( f () );
022</script>

プログラムを実行すると「IORI」と表示する。

先ほどのプログラムを改善する方法として、クロージャが広く知られている。

18行目から解説する。18行目でioriオブジェクトのfactory()関数を実行して、 戻り値を変数fへ代入する。

7行目のfactory()関数を解説する。 10行目でthisの値を変数thatへ代入する。 この時点で、thisの値はioriオブジェクトを意味する。 そのオブジェクトを変数thatへ代入する。11行目で関数を戻す。 戻り値の関数で変数thatを利用している。 関数内から関数外の変数を利用する時、 関数と変数はセットで存在する。 つまり、factory()関数の処理終了後も変数thatは存続して、 ioriオブジェクトを参照し続ける。

001<script>
002//ioriオブジェクト
003var iori = {
004  x : "IORI" ,
005  
006  //関数を戻す
007  factory : function () {
008  
009    //クロージャ
010    var that = this ;
011    return function () {
012      return that.x ;
013    }
014  }
015}
016//factory()関数を実行して
017//関数を受け取る
018var f = iori.factory () ;
019
020//[IORI]
021alert ( f () );
022</script>

21行目で関数f()を実行する。関数f()はfactory()関数の戻り値である。

001<script>
002alert (
003    {
004      //クロージャ
005      var that = this ;
006      
007      function () {
008        return that.x ;
009      }
010    }
011);
012</script>

関数f()は変数thatとセットになっている。 変数thatには、ioriオブジェクトが入っている。 プログラムを実行すると、ioriオブジェクトのxプロパティの値「IORI」が ダイアログに表示する。 解説は以上である。

配列のforEach()関数とthisの関係

配列のforEach()関数とthisの関係を見る。

001<script>
002//オブジェクトを作成
003var iori = {
004  //配列を作成
005  names : [ "IORI" , "iori" ] ,
006  
007  //prefixを定義
008  prefix : "走る"
009}
010//getNames()関数
011iori.getNames = function () {
012  
013  //forEach()関数で全ての要素を取得
014  this.names.forEach (
015    
016    function ( name , i , names ) {
017      alert ( this.prefix + name );
018    }
019  ) ;
020}
021//[undefinedIORI][undefinediori]
022iori.getNames();
023</script>

プログラムを実行すると「undefinedIORI」、「undefinediori」と表示する。

プログラムを実行すると「undefined」と表示するので、気をつける必要がある。 解説する。3行目でioriオブジェクトを作成する。 オブジェクトのプロパティはnames配列とprefix文字列である。 11行目でioriオブジェクトにgetNames()関数を追加する。関数の処理は後ほど見る。 22行目で、getNames()関数を実行する。

011iori.getNames = function () {
012  
013  //forEach()関数で全ての要素を取得
014  this.names.forEach (
015    
016    function ( name , i , names ) {
017      alert ( this.prefix + name );
018    }
019  ) ;
020}

getNames()関数を解説する。14行目でnames配列のforEach()関数を実行する。 14行目のthisはioriオブジェクトである。 問題は、forEach()関数に渡した関数の中のthisである(17行目のthis)。 forEach()関数の引数に渡す関数は、16行目から18行目までである。 17行目のthis.prefixは、一見ioriオブジェクトのprefixプロパティを参照していそうだが、 そうではない。17行目のthisはwindowオブジェクトである。 現在windowオブジェクトにprefixプロパティは存在しないので、 this.prefixの値は「undefined」である。 解説は以上である。

このプログラムを正しく改善する方法をざっと見る。

001<script>
002//オブジェクトを作成
003var iori = {
004  //配列を作成
005  names : [ "IORI" , "iori" ] ,
006  
007  //prefixを定義
008  prefix : "走る"
009}
010//getNames()関数
011iori.getNames = function () {
012  
013  //forで全ての要素を取得
014  for ( var i = 0 ; i < this.names.length ; i++ ) {
015    alert ( this.prefix + this.names[i] );
016  }
017}
018//[走るIORI][走るiori]
019iori.getNames();
020</script>

プログラムを実行すると「走るIORI」、「走るiori」と表示する。

forEach()関数を諦めて、通常のfor文で処理する解決方法である。 どうでしょうか?

001<script>
002//オブジェクトを作成
003var iori = {
004  //配列を作成
005  names : [ "IORI" , "iori" ] ,
006  
007  //prefixを定義
008  prefix : "走る"
009}
010//getNames()関数
011iori.getNames = function () {
012
013  var that = this ;
014  
015  //forEach()関数で全ての要素を取得
016  this.names.forEach (
017    
018    function ( name , i , names ) {
019      alert ( that.prefix + name );
020    }
021  ) ;
022}
023//[走るIORI][走るiori]
024iori.getNames();
025</script>

プログラムを実行すると「走るIORI」、「走るiori」と表示する。

13行目でthisを変数thatへ代入する。 このthatは19行目で利用する。 関数の中の関数でthisを利用すると、thisの挙動は不安定になる。 それならば、thisを利用するのではなく、 代わりに変数thatを参照させる。 変数thatはただの変数である。

プロトタイプチェーンとthis

最後にプロトタイプチェーンとthisの関係を見て、 本講座を閉じる。

001<script>
002//Itemコンストラクタ関数
003var Item = function ( ) {
004  this.x = "item" ;
005}
006//run()関数
007Item.prototype.run = function ( ) {
008  return this.x ;
009} ;
010//Ioriオブジェクト
011var Iori = function ( ) {
012  this.x = "iori" ;
013}
014//プロトタイプチェーン
015Object.setPrototypeOf (
016  Iori.prototype ,
017  Item.prototype
018) ;
019//Iori型オブジェクト
020const iori = new Iori () ;
021
022//[iori]
023alert ( iori.run () ) ;
024</script>

プログラムを実行すると「iori」と表示する。

解説する。3行目でItemコンストラクタ関数を定義する。 7行目でItemコンストラクタ関数のprototypeオブジェクトにrun()関数を追加する。 11行目でIoriコンストラクタ関数を定義する。 15行目で、Object.setPrototypeOf()関数を実行して、 Itemコンストラクタ関数とIoriコンストラクタ関数の間に、 プロトタイプチェーンを構築する。 20行目でIoriコンストラクタ関数をnewして、変数ioriへ代入する。 ここで、オブジェクトの関係を見る。

オブジェクト Iori Item
変数
iori
x: "IORI"
__proto__ : {

  【参照X】

}
prototype : {

  【参照X】

  __proto__ : {

    【参照Y】

  }
}

prototype : {

  【参照Y】

  run : function

  __proto__ : {

  }
}

このような状態になる。変数ioriが参照するオブジェクトには、 xプロパティが存在する。他のコンストラクタ関数にはxプロパティは存在しない。 newをしなければ、コンストラクタ関数はただの関数である。 newした時に、プロパティが入ったオブジェクトを戻す。

023alert ( iori.run () ) ;

23行目で変数ioriが参照するオブジェクトに対してrun()関数を実行する。 オブジェクトはrun()関数を持っていない。 そのため、プロトタイプチェーンをさかのぼってrun()関数を探す。 Itemコンストラクタ関数のprototypeオブジェクトの中にrun()関数が存在する。 このrun()関数が実行する。

007Item.prototype.run = function ( ) {
008  return this.x ;
009} ;

run()関数を実行すると、オブジェクトのxプロパティが戻る。 8行目のthisは現在実行中のオブジェクト、「ioriオブジェクト」である。 プログラムを実行すると「iori」とダイアログに表示する。

解説は以上である。

まとめ

this プログラムを実行した時のオブジェクトである。