情報学部 菅沼ホーム 目次 索引

JavaScript 概説

  1. JavaScript の特徴とその使用方法
    1. HTML ファイル内へ記述
    2. 外部ファイルへ記述
    3. HTML 要素内へ記述
  2. データ型
  3. 演算子
    1. 算術演算子と代入演算子
    2. 関係演算子,等値演算子,及び,論理演算子
    3. ビット演算子とシフト演算子
    4. その他
  4. 制御文
    1. 分岐
    2. 繰り返し
  5. 配列
    1. 1 次元配列
    2. 多次元配列
    3. 連想配列
  6. 関数
    1. [プログラム例 6.1] 関数(様々な引数)
    2. [プログラム例 6.2] 関数(関数名)
  7. クラスとオブジェクト
    1. [プログラム例 7.1] 新規オブジェクトの定義と利用
    2. [プログラム例 7.2] クラスの定義と利用
  8. 変数の有効範囲(スコープ)

  1. JavaScript の特徴とその使用方法

    1. HTML ファイル内へ記述

        HTML ファイル内に JavaScript を記述する場合は,SCRIPT 要素を使用し,
      <SCRIPT TYPE="text/javascript">
      	<!--
      		ここに,JavaScript のプログラム
      	//-->
      </SCRIPT>				
      のように記述します.なお,「<!--」と「//-->」は,JavaScript に未対応のブラウザが JavaScript のソースプログラムをコメントアウトするためです.このサイトの目的から言って,必要ないと思いますので,基本的には省略します.

        使用例1のように記述すると,ページが表示されたときに 12 行目~ 24 行目に記述された JavaScript も実行されます.13 行目によって,メッセージが表示され,14 行目~ 24 行目によって,新しい Window が表示されます.なお,プログラムの意味については,現時点では,あまり気にしないで下さい.

      使用例1( use1.htm )

      01	<!DOCTYPE HTML>
      02	<HTML>
      03	<HEAD>
      04		<TITLE>文書内記述</TITLE>
      05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
      06		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
      07		<LINK REL="stylesheet" TYPE="text/css" HREF="../../master.css">
      08	</HEAD>
      09	<BODY CLASS="white">
      10		<H1 CLASS="center">文書内記述</H1>
      11		<SCRIPT TYPE="text/javascript">
      12			document.write("JavaScript によって出力<BR>\n");
      13			alert("文書内記述");
      14			let w = window.open("", "", "width=300, height=100");
      15			w.document.open();
      16			w.document.write('<HTML>\n');
      17			w.document.write('	<HEAD>\n');
      18			w.document.write('		<TITLE>新しい Window</TITLE>\n');
      19			w.document.write('	</HEAD>\n');
      20			w.document.write('	<BODY>\n');
      21			w.document.write('		新しい Window の生成も可能<BR>\n');
      22			w.document.write('	</BODY>\n');
      23			w.document.write('</HTML>\n');
      24			w.document.close();
      25		</SCRIPT>
      26	</BODY>
      27	</HTML>
      				
        ページが表示されたときには実行されず,マウスでクリックしたときに実行したいような場合は,使用例2のように,HEAD 要素の中に実行したいことを関数の形で記述しておき,指定された箇所がクリックされる(イベントが発生する)と,その関数が実行されるようにすることも可能です.この例では,16 行目に記述された onClick 属性によって,09 行目~ 12 行目に記述された関数 func が実行され,メッセージが表示されます.なお,イベント処理に関しては,「 event オブジェクト」,「HTML のグローバル属性」などを参照してください.

      使用例2( use2.htm )

      01	<!DOCTYPE HTML>
      02	<HTML>
      03	<HEAD>
      04		<TITLE>文書内記述(関数)</TITLE>
      05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
      06		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
      07		<LINK REL="stylesheet" TYPE="text/css" HREF="../../master.css">
      08		<SCRIPT TYPE="text/javascript">
      09			function func()
      10			{
      11				alert("文書内記述(関数)");
      12			}
      13		</SCRIPT>
      14	</HEAD>
      15	<BODY CLASS="white">
      16		<H1 CLASS="center">文書内記述(関数)(<SPAN onClick="func()">ここをクリック</SPAN>)</H1>
      17	</BODY>
      18	</HTML>
      				

    2. 外部ファイルへ記述

        JavaScript の関数などを外部ファイルに記述し,それを呼び出すことも可能です.たとえば,使用例2の場合,HEAD 要素内に,
      01	<!DOCTYPE HTML>
      02	<HTML>
      03	<HEAD>
      04		<TITLE>外部ファイル</TITLE>
      05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
      06		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
      07		<LINK REL="stylesheet" TYPE="text/css" HREF="../../master.css">
      08		<SCRIPT TYPE="text/javascript" SRC="control.js"></SCRIPT>
      09	</HEAD>
      10	<BODY CLASS="white">
      11		<H1 CLASS="center">外部ファイル(<SPAN onClick="func()">ここをクリック</SPAN>)</H1>
      12	</BODY>
      13	</HTML>
      				
      のような記述をし( 8 行目の SCRIPT 要素),そこで指定したファイル control.js に,関数 func を
      function func()
      {
      	alert("外部ファイル");
      }				
      のように記述することによっても実現可能です(使用例3).

    3. HTML 要素内へ記述

        実行する JavaScript の命令などが少ない場合は,使用例4のように,HTML 要素内に記述することも可能です.この例では,SPAN 要素( 11 行目)と A 要素( 12 行目)内に記述しています.いずれの場合も,2 つの alert 関数が順に実行されます.
      01	<!DOCTYPE HTML>
      02	<HTML>
      03	<HEAD>
      04		<TITLE>要素内記述</TITLE>
      05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
      06		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
      07		<LINK REL="stylesheet" TYPE="text/css" HREF="../../master.css">
      08	</HEAD>
      09	<BODY CLASS="white">
      10		<H1 CLASS="center">要素内記述</H1>
      11		SPAN 要素  <SPAN onClick="JavaScript: alert('alert 1');alert('alert 2')">ここをクリック</SPAN><BR><BR>
      12		A 要素  <A HREF="JavaScript: alert('alert 2');alert('alert 1')">ここをクリック</A>
      13	</BODY>
      14	</HTML>
      				

  2. データ型

      JavaScript では,C/C++ や Java のように,変数に対して型宣言を行う必要はありません.代入されたデータによって,自動的にその変数の型が決定されます.例えば,
    let x1 = 12345;
    let x2;
    var y1 = 12.5;
    var y1;
    z1 = 12;
    z1;
    			
    のような形で変数の使用を開始すると(変数を定義すると),それ以降,その変数を使用することが出来るように(有効に,参照可能に)なります.ブロック内( { } で囲まれた部分,関数も含む)で,let を指定して定義すると,ブロック内のその変数が定義された以降で有効になります.また,関数内で,var を指定して定義すると,関数内のその変数が定義された以降で有効になります.これらの変数をローカル変数と呼びます.関数外で定義された変数,または,let や var を付加せずに定義された変数は,グローバル変数と呼ばれ,変数が定義された以降であれば,どこからでも参照可能(有効)になります.誤りの原因となりやすいので,「グローバル変数は,関数の外で let や var を付加せずに定義する,ローカル変数は,特別の理由が無い限り,var ではなく let を付加して定義する」といった規則を守った方が良いと思います.詳細については,変数の有効範囲(スコープ)を参照してください.

      JavaScript で使用できる型や特別な定数は以下に示す通りです.

    • 数値: 10 進整数,8 進数( 0 で始まる),16 進数( 0x で始まる),浮動小数点数を使用できます.整数と浮動小数点数は区別されず,すべて,8 バイトの浮動小数点数として表現されます.表現可能な範囲は,
      ±1.7976931348623157 × 10308				
      となります.また,整数として精度が保証されるのは,
      -253(-9,007,199,254,740,992) ~ 253(9,007,199,254,740,992)				
      の範囲です.

    • 文字列: ダブルクォ-テンションマーク「 " 」,または,シングルクォ-テンションマーク「 ' 」で囲まれた文字や数字です.両者に差はなく,「"abc"」と「'abc'」は全く同じ文字列になります.さらに,+ 演算子によって,文字列の結合が可能です.また,片方を他方に組み入れることも可能であり,例えば,
      let x = "<SPAN STYLE='red'>赤</SPAN>"				
      と記述すれば,シングルクォ-テンションマークが,一つの文字として文字列の中に組み込まれます(シングルクォ-テンションマークとダブルクォ-テンションマークを入れ替えても同様).

    • 論理値: truefalse の値を持ちます.false,0,"",null,undefined,NaN 以外は true となります.また,C/C++ と同様,結果に対して数値演算が可能です.

    • null: 何も設定されていないことを表します.

    • undefined: 定義されていないことを表します.

    • NaN: 数値でないことを表します.

    • Infinity: 無限であることを表します.

  3. 演算子

    1. 算術演算子代入演算子

        整数同士の除算であっても,C/C++ のように,小数点以下が切り捨てられないことに注意してください.小数点以下を切り捨てたい場合は,Math オブジェクト内のメソッド ceilfloor などを使用してください.また,C/C++ と同様,演算と代入を同時に行う演算子,例えば,「 x += 10; 」なども使用可能です.
      + : 加算 : どちらかが文字列の場合は,文字列の結合
      - : 減算
      * : 乗算
      / : 除算 : 整数同士の割り算であっても,小数点以下が切り捨てられません.
      % : 余り : 被除数,除数は共に制限はありません.除算の結果を整数として,その余りを結果とします.
               例えば,7.3 % 2.3 の結果は 0.4 となります( 7.3 / 2.3 の演算結果は,3 余り 0.4 ).
      = : 代入
      ++ : インクリメント演算子( 1 だけ増加)
      -- : デクリメント演算子( 1 だけ減少)				
    2. 関係演算子等値演算子,及び,論理演算子
      >  より大きい  a > b   式 a の値が式 b の値より大きいとき真
      <  より小さい  a < b   式 a の値が式 b の値より小さいとき真
      >= 以上     a >= b  式 a の値が式 b の値以上のとき真
      <= 以下     a <= b  式 a の値が式 b の値以下のとき真
      == 等しい     a == b  式 a の値と式 b の値が等しいとき真
      === 等しい    a === b  式 a の値と式 b の値が等しいとき真(型の変更を行わない.例えば,「 true == 1 」は真となるが,「 true === 1 」は偽となる)
      != 等しくない   a != b  式 a の値と式 b の値が等しくないとき真
      !== 等しくない  a !== b  式 a の値と式 b の値が等しくないとき真(型の変更を行わない.例えば,「 true == 1 」は真となるが,「 true === 1 」は偽となる)
      || 論理和  x || y  式 x が真か,または,式 y が真のとき真
      && 論理積  x && y  式 x が真で,かつ,式 y が真のとき真
      !  否定    ! x      式 x が偽のとき真				

    3. ビット演算子シフト演算子
      | 論理和      x | y   対応するビットのいずれかが 1 のとき真.
      & 論理積      x & y   対応するビットの双方が 1 のとき真
      ^ 排他的論理和 x ^ y   対応するビットが異なるのとき真
      ~ 1の補数     ~ x      ビット毎に 1 と 0 を反転する
      << 左にシフト   x << 3  3 ビット左にシフト.x を 23 倍することに相当.
      >> 右にシフト   x >> 3  3 ビット右にシフト.x を 23 で割ることに相当.
      >>> 右にシフト  x >>> 3  3 ビット右にシフト( C++ における符号無しの整数を右シフトする場合に相当).				

    4. その他
      new     let obj = new Date() オブジェクトの生成
      delete  delete obj オブジェクトの削除(配列の要素も可能)
                   例 delete a[2];
                     delete['xyz'];   // 連想配列
      typeof() typeof(x) 変数などの型
      in 数値  in obj オブジェクト内に指定した値が含まれていれば真
                   例 let a = new Array(1,2,3);
                     document.write(5 in a);				
  4. 制御文

    1. 分岐

      • if 文
        if (論理式) {
        	文1(複数の文も可)
        }
        else {
        	文2(複数の文も可)
        }					

      • else if 文
        if (論理式) {
        	文1(複数の文も可)
        }
        else if (論理式) {
        	文2(複数の文も可)
        }
          ・・・
        else {
        	文n(複数の文も可)
        }					

      • switch 文

        switch (式) {
        	[case 定数式1 :]
        		[文1]
        	[case 定数式2 :]
        		[文2]
        	 ・・・・・
        	[default :]
        		[文n]
        }					

    2. 繰り返し

      • for 文
        for (初期設定; 繰り返し条件; 後処理) {
        	文(複数の文も可)
        }
           ・・・					

      • while 文
        while (繰り返し条件) {
        	文(複数の文も可)
        }					
      • do while 文
        do {
        	文(複数の文も可)
        } while (繰り返し条件) ;					

      • for in 文

          この機能は,C/C++ における「範囲 for 文」と似ていますが,かなり異なった動作をします.

        for (変数名 in オブジェクト名) {
        	文(複数の文も可)
        }					

  5. 配列

    1. 1 次元配列

        配列は,複合データ型の一種であり,複数のデータを処理する場合に利用されます.例えば,
      let x1 = new Array();   // 要素数は未定
      let x2 = new Array(100);   // 要素数が100の配列
      let x3 = new Array(1, 2.3, "abc");   // 初期設定も実施
      let x4 = [1, 2.3, "abc"];   // 上と同様				
      の 3,4 行目のように宣言すれば,3 つのデータを記憶できる領域が確保され,各要素に記憶される値が 1,2.3,"abc" で初期設定されます.また,変数名と添え字を利用して,x[0],x[1],x[2] のようにして参照できます(添え字が,0 から始まることに注意).この例に示すように,各要素は,必ずしも,同じデータ型である必要はありません.しかし,間違いの元になる可能性がありますので,配列は,同じデータ型だけで構成するようにした方が良いと思います.また,プログラムの実行時に,要素の追加,削除等を行うことが可能です.

    2. 多次元配列

        多次元の配列を扱うことも可能です.例えば,

      let v1 = new Array(2);
      v1[0] = new Array(10, 20, 30);
      v1[1] = new Array(40, 50, 60);				
      のように,配列の要素を,さらに配列として定義すれば,2 次元の配列を定義できます.この例では,2 行 3 列の配列になります.

    3. 連想配列

        連想配列を使用することも可能です.連想配列は,キーと値のペアで構成され,例えば,
      let color = {'red' : '赤', 'blue' : '青'};
      let color = {red : '赤', blue : '青'};   // 上と同様				
      のように記述します.キーの部分('red','blue')は,文字列に限定されますが,値の部分はどのようなデータでも構いません.また,初期設定を行わず,
      let color     = new Array();
      color['red']  = '赤';
      color['blue'] = '青';				
      のような記述も可能です.

  6. 関数

      関数は,何らかの処理を行い,その結果を返しますが,処理を行うためには外部からの情報を必要とする場合があります.ここで,引数とは,関数を呼び出した側と関数との間で,情報の受け渡しに使用される変数や定数のことです.また,関数は,計算した結果を関数を呼び出した側に戻したい場合がありますが,その際は,以下にあげるプログラム例に示すように,return 文を使用します.関数に対する一般的記述方法は,

    function 関数名 (引数, ・・・) {
    	処理
    }			
    のようになります.なお,一般に,関数の記述は HEAD 要素内で行います.

    プログラム例 6.1] 関数(様々な引数)

      プログラムでは,2 つの値,配列,及び,クラスのオブジェクトを引数として渡し,5 番目の引数はデフォルト引数であるため,省略しています.なお,クラスに関しては,次章を参照してください.

    01	<!DOCTYPE HTML>
    02	<HTML>
    03	<HEAD>
    04		<TITLE>関数(様々な引数)</TITLE>
    05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
    06		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
    07		<LINK REL="stylesheet" TYPE="text/css" HREF="../../master.css">
    08		<SCRIPT TYPE="text/javascript">
    09					// クラス Complex
    10			class Complex {
    11						// コンストラクタ
    12				constructor(a, b)
    13				{
    14					this.x = a;
    15					this.y = b;
    16				}
    17			}
    18					// 関数 func
    19			function func(a, b, c, d, e = 5)
    20			{
    21				d.x  = -100;
    22				a   += 10;
    23				c[0] = 30;
    24				return (a + b + e);   // 計算結果を返す
    25			}
    26		</SCRIPT>
    27	</HEAD>
    28	<BODY CLASS="white">
    29		<H1 CLASS="center">関数(様々な引数)</H1>
    30		<SCRIPT TYPE="text/javascript">
    31			let x = 1;
    32			let y = 2;
    33			let z = new Array(10, 20);
    34			let w = new Complex(100, 200);
    35			document.write("関数を呼ぶ前:<BR>\n");
    36			document.write("   x:" + x + " y:" + y + " z:" + z[0] + "," + z[1] + " w.x:" + w.x + "<BR>\n");
    37			let r = func(x, y, z, w);
    38			document.write("関数を呼んだ後:<BR>\n");
    39			document.write("   x:" + x + " y:" + y + " z:" + z[0] + "," + z[1] + " w.x:" + w.x + " r:" + r + "<BR>\n");
    40		</SCRIPT>
    41	</BODY>
    42	</HTML>
    			
    10 行目~ 17 行目

      クラス Complex の定義です.

    19 行目~ 25 行目

      2 つの値,配列,及び,クラスのオブジェクトを引数とした関数 func の定義です.21 行目で Complex クラスのオブジェクト d ( 34 行目の w に対応)における x の値,22 行目で変数 a ( 31 行目の x に対応)の値,また,23 行目では c[0] ( 33 行目の z[0] に対応)を変更しています.

      また,19 行目では,5 つの引数が定義されていますが,37 行目では 4 つの引数しか設定されておらず,5 番目の引数が省略されています.このような場合,5 番目の引数の値として 19 行目の e に設定されている 5 という値が使用されます.このような省略可能な引数をデフォルト引数と呼び,引数の最後に複数個設定可能です.

    33 行目

      配列変数 z を定義しています( 10 と 20 で初期設定).

    34 行目

      Complex クラスのオブジェクト w を生成しています( 100 と 200 で初期設定).

    35,36 行目

      関数 func を呼ぶ前の変数 x,y,z,w を出力しています.設定したとおりの値が出力されています.

    37 行目

      4 つの変数を引数として,関数 func を呼んでいます.

    38,39 行目

      関数 func を呼んだ後の変数 x,y,z,w,及び,計算結果 r を出力しています.関数を呼ぶ際,引数は,その値がコピーされて関数に渡されます.上の例では,37 行目において,各変数の値がコピーされ,19 行目の各変数に渡されます.従って,関数内において,a の値を変更( 22 行目)しても x の値は変化しません.しかし,配列(変数 z )やクラスのオブジェクト(変数 w )のようなオブジェクトを引数として場合は,C/C++ におけるアドレスを引数とした場合に相当し,関数内においてオブジェクトの値を変更すれば,関数を呼んだ側におけるオブジェクトの値も変化します.この出力結果からも明らかなように,x,y の値は変化していないのに,z[0],w.x の値は変化しています.

    プログラム例 6.2] 関数(関数名) 

      関数も一つのオブジェクトです.従って,関数(のアドレス)を他の変数に代入すれば,その変数は関数と同じように使用できます.また,関数(のアドレス)を関数の引数としても使用可能です.このプログラムは,そのような例を示しています.

    01	<!DOCTYPE HTML>
    02	<HTML>
    03	<HEAD>
    04		<TITLE>関数(関数名)</TITLE>
    05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
    06		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
    07	</HEAD>
    08	<BODY>
    09		<SCRIPT TYPE="text/javascript">
    10			function add(s1, s2) {
    11				let s = s1 + s2;
    12				return s;
    13			}
    14	
    15			function sub(s1, s2) {
    16				let s = s1 - s2;
    17				return s;
    18			}
    19	
    20			function add_sub(fun, s1, s2) {
    21				let s = fun(s1, s2);
    22				return s;
    23			}
    24	
    25			document.write("add(2,3) " + add(2,3) + "<BR>\n");
    26	
    27			let kasan = add;
    28			document.write("kasan(2,3) " + kasan(2,3) + "<BR>\n");
    29	
    30			document.write("add_sub(add, 2, 3) " + add_sub(add, 2, 3) + "<BR>\n");
    31			document.write("add_sub(sub, 2, 3) " + add_sub(sub, 2, 3) + "<BR>\n");
    32		</SCRIPT>
    33	</BODY>
    34	</HTML>
    			
    10 行目~ 13 行目

      2 つの引数の和を計算して返す関数です.

    15 行目~ 18 行目

      2 つの引数の差を計算して返す関数です.

    20 行目~ 23 行目

      引数として渡された関数 fun を呼び,その結果を返す関数です.

    25 行目

      関数 add を呼んでいます.

    27,28 行目

      関数 add (のアドレス)を,変数 kasan に代入し,この変数を利用して関数 add を呼んでいます.このように,変数 kasan は,関数 add と同様の働きをします.

    30,31 行目

      関数 add_sub の引数として,add または sub を渡して,いずれかの計算結果を得ています.

  7. クラスとオブジェクト

      クラスとモジュールは,その表現方法は多少異なりますが,使用方法の点からから見て非常に似ています.その大きな違いの一つは,ここでは述べませんが,クラスには継承という機能があることです.

    プログラム例 7.1] 新規オブジェクトの定義と利用

      プログラムは,複素数をイメージしたオブジェクトを作成したものです.クラスとはかなり異なっていますが,すべての変数や関数をグローバルな状態にすることを多少避けることができます.なお,JavaScript においては,クラスやオブジェクト内の関数を,メソッドと呼んでいます.
    01	<!DOCTYPE HTML>
    02	<HTML>
    03	<HEAD>
    04		<TITLE>オブジェクト</TITLE>
    05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
    06		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
    07		<LINK REL="stylesheet" TYPE="text/css" HREF="../../master.css">
    08		<SCRIPT TYPE="text/javascript">
    09						// Complex オブジェクト(プロパティ)
    10			function Complex(a, b)
    11			{
    12				this.x = a;
    13				this.y = b;
    14				this.r = this.rep();
    15			}
    16						// Complex オブジェクト(メソッド add )
    17			Complex.prototype.add = function(b)
    18			{
    19				let cp = new Complex(this.x + b.x, this.y + b.y);
    20				return cp;
    21			}
    22						// Complex オブジェクト(メソッド rep )
    23			Complex.prototype.rep = function()
    24			{
    25				let r = "(" + this.x + " , " + this.y + ")";
    26				return r;
    27			}
    28		</SCRIPT>
    29	</HEAD>
    30	<BODY CLASS="white">
    31		<H1 CLASS="center">新規オブジェクトの定義と利用</H1>
    32		<SCRIPT TYPE="text/javascript">
    33			let cp1 = new Complex(1, 2);
    34			let cp2 = new Complex(3, 1);
    35			let cpa = cp1.add(cp2);   // cp2.add(cp1) でも同じ
    36			document.write("cp1 + cp2 = (" + cpa.x + " , " + cpa.y + ")<BR>\n");
    37			document.write(cp1.r + " + " + cp2.r + " = " + cpa.r + "<BR>\n");
    38		</SCRIPT>
    39	</BODY>
    40	</HTML>
    			
    10 行目~ 15 行目

      33,34 行目のように,Complex オブジェクトが生成されると,最初に呼ばれる関数です.引数として渡された変数が,Complex オブジェクトのプロパティ( C++ におけるメンバー変数に対応) x,y に代入されます.this とは,自分自身を指すキーワードであり,これを記述しないと,x,y の値が正しく設定されません.14 行目のメソッド rep ( 23 行目~ 27 行目に定義)は,x,y の値を "(x, y)" のような文字列に変換します.this が必要な箇所に注意してください.

    17 行目~ 21 行目,23 行目~ 26 行目

      メソッド add は,自分自身と Complex オブジェクト b の加算を行い,結果として得られた Complex オブジェクトを返します.35 行目で使用しています.add と rep は,Complex オブジェクトのメソッド( C++ におけるメンバー関数に相当)です.prototype というキーワードと,その使用方法に注意してください.

    36 行目

      Complex オブジェクトのプロパティ x,y を直接使用して,加算結果を出力しています.

    37 行目

      Complex オブジェクトのプロパティ r を使用して,加算結果を出力しています.

    プログラム例 7.2] クラスの定義と利用 

      プログラムは,プログラム例 7.1 を,クラスを利用して修正・追加したものです.基本的に,オブジェクトやクラスにおけるプロパティやメソッドは,オブジェクトやクラスの外部から参照可能です.しかし,クラスの場合は,プロパティやメソッドの前に # を付加することによって,外部から参照できなくすることが可能です( C++ における private 指定に対応).以下に示すプログラムにおいては,Complex クラスと,それを継承した Real クラスを扱っています.

    01	<!DOCTYPE HTML>
    02	<HTML>
    03	<HEAD>
    04		<TITLE>クラス</TITLE>
    05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
    06		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
    07		<LINK REL="stylesheet" TYPE="text/css" HREF="../../master.css">
    08		<SCRIPT TYPE="text/javascript">
    09					// クラス Complex
    10			class Complex {
    11				static name = "Complex Number";
    12				#y = 0;
    13						// コンストラクタ
    14				constructor(a, b)
    15				{
    16					this.x = a;
    17					this.#y = b;
    18					this.r = this.rep();
    19				}
    20						// メソッド add
    21				add = function(b)
    22				{
    23					let cp = new Complex(this.x + b.x, this.#y + b.#y);
    24					return cp;
    25				}
    26						// メソッド sub
    27				static sub = function(a, b)
    28	//			static sub = function(b)
    29				{
    30					let cp = new Complex(a.x - b.x, a.#y - b.#y);
    31	//				alert("name: " + this.name + " x: " + this.x);   // x に対しては,undefined
    32	//				let cp = new Complex(this.x - b.x, this.#y - b.#y);
    33					return cp;
    34				}
    35						// メソッド rep
    36				rep = function()
    37				{
    38					let r = "(" + this.x + " , " + this.#y + ")";
    39					return r;
    40				}
    41			}
    42					// クラス Real
    43			class Real extends Complex {
    44				static name = "Real Number";
    45						// コンストラクタ
    46				constructor(a)
    47				{
    48					super(a, 0);
    49					this.r = this.rep();
    50				}
    51						// メソッド rep
    52				rep = function()
    53				{
    54					return this.x;
    55				}
    56			}
    57		</SCRIPT>
    58	</HEAD>
    59	<BODY CLASS="white">
    60		<H1 CLASS="center">クラスの定義と利用</H1>
    61		<SCRIPT TYPE="text/javascript">
    62					// Complex
    63			document.write("  ***" + Complex.name + "***<BR>\n");
    64			let cp1 = new Complex(1, 2);
    65			let cp2 = new Complex(3, 1);
    66			let cpa = cp1.add(cp2);   // cp2.add(cp1) でも同じ
    67			let cps = Complex.sub(cp1, cp2);
    68	//		document.write("cp1 + cp2 = (" + cpa.x + " , " + cpa.#y + ")<BR>\n");   // エラー
    69			document.write(cp1.r + " + " + cp2.r + " = " + cpa.r + "<BR>\n");
    70			document.write(cp1.r + " - " + cp2.r + " = " + cps.r + "<BR>\n");
    71					// Real
    72			document.write("  ***" + Real.name + "***(Complex.name: " + Complex.name + ")<BR>\n");
    73			let re1 = new Real(10);
    74			let re2 = new Real(20);
    75			let rea = re1.add(re2);   // re2.add(re1) でも同じ
    76			let res = Real.sub(re1, re2);
    77			document.write(re1.r + " + " + re2.r + " = " + rea.x + "<BR>\n");
    78			document.write(re1.r + " - " + re2.r + " = " + res.x + "<BR>\n");
    79		</SCRIPT>
    80	</BODY>
    81	</HTML>
    			
    10 行目~ 41 行目

      クラス Complex の定義です.変数 name に対しては,static 宣言されていますので( 11 行目),静的変数となり,クラスのインスタンスが生成される前でも,後でも,「クラス名.変数名」という形で参照します( 63 行目).また,変数 y に対しては,# が付加されていますので( 12 行目),クラス外部から参照することはできませんし( 68 行目),継承もされません.

    14 行目~ 19 行目

      64,65 行目のように,Complex オブジェクトが生成されると,最初に呼ばれるメソッドであり,コンストラクタconstructor )と呼ばれます.

    21 行目~ 25 行目

      Complex クラスのメソッド add の定義です.2 つの Complex オブジェクトの加算を行います.

    27 行目~ 34 行目

      Complex クラスのメソッド sub の定義です.2 つの Complex オブジェクトの減算を行います.27 行目において static 指定がしてありますので,静的メソッドとなり,「クラス名.メソッド」という形で参照されます( 67 行目).静的メソッドは,静的変数以外の変数を直接参照できないため,28,31,32 行目のような記述はエラーになります.

    36 行目~ 40 行目

      Complex クラスのメソッド rec の定義です.Complex オブジェクトを,「(x, y) 」のような形に変形した文字列を返します.

    43 行目~ 56 行目

      Complex クラスを継承した Real クラスの定義です.コンストラクタは継承されませんので,Real クラスのコンストラクタ内から,super を使用して,親クラスのコンストラクタを呼び出しています( 48 行目).static 変数 name は,その性質だけが継承され,値は継承されません.44 行目の記述がないとクラス名 Real が入ります.

    52 行目~ 55 行目

      Complex クラスから継承した rep メソッドをオーバーライド(書き直し)をしています.

    63 行目~ 70 行目

      Complex クラスのオブジェクトを生成し,その加算と減算を行っています.add と sub の参照方法の違いに注意してください.

    72 行目~ 78 行目

      Real クラスのオブジェクトを生成し,その加算と減算を行っています.72 行目では,static 変数 name を出力しています.継承した add や sub の結果 rea や res は,Complex 型となり,その変数 r は,(x, 0) のような形をしています.従って,77,78 行目においては,rea.x,res.x のように x の値を直接出力しています.

  8. 変数の有効範囲(スコープ) 

      ここをクリックすれば,ブラウザ上で実行することができます.表示された画面において,「 OK 」ボタンをクリックすると,テキストエリアに,実行結果が表示されます.

    01	<!DOCTYPE HTML>
    02	<HTML>
    03	<HEAD>
    04		<TITLE>変数の有効範囲(スコープ)</TITLE>
    05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
    06		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
    07		<SCRIPT TYPE="text/javascript">
    08			/****************************/
    09			/* 変数の有効範囲(スコープ) */
    10			/*      coded by Y.Suganuma */
    11			/****************************/
    12	
    13			str = "";
    14			z   = 30;
    15	
    16			/************************/
    17			/* オブジェクト Example */
    18			/************************/
    19			function Example() {  // class Example {
    20				this.x = 1000;   // constructor() { this.x = 1000; }
    21			}
    22	
    23			Example.prototype.sub = function() {   // sub = function() {
    24				str += "sub member( x ) " + this.x + "\n";
    25			}
    26	
    27			/************/
    28			/* 関数 run */
    29			/************/
    30			function run() {
    31						// ブロック
    32				let x = 10;
    33				var a = 100;
    34				if (x > 5) {
    35	//				str  += "then block x " + x + "\n";   // 許されない
    36					str  += "then block a " + a + "\n";
    37					let x = 15;
    38					if (x > 7) {
    39						let x = 20;   // OK
    40						str  += "then block block x " + x + "\n";
    41					}
    42					var a = 200;
    43					let b = -100;
    44					var y = 20;
    45					str  += "then block x " + x + "\n";
    46					str  += "then block a " + a + "\n";
    47					str  += "then block b " + b + "\n";
    48					str  += "then block y " + y + "\n";
    49				}
    50				else {
    51					str += "else block x " + x + "\n";
    52					str += "else block a " + a + "\n";
    53					x    = -15;
    54					str += "else block x " + x + "\n";
    55				}
    56	//			let x = 100;   // 許されない
    57	//			var a = 300;   // 許される
    58	//			str += "w " + w + "\n";   // 許されない
    59				sub();
    60				str += "w " + w + "\n";   // グローバル変数
    61				str += "x " + x + "\n";
    62				str += "a " + a + "\n";
    63	//			str += "b " + b + "\n";   // 許されない
    64				str += "y " + y + "\n";   // ブロック内の定義が有効
    65				                          // 最初の x が 1 の時は undefined
    66						// オブジェクト
    67				let ex = new Example();
    68				ex.sub();
    69				str += "member( x ) " + ex.x + "\n";
    70					//
    71					// 結果の設定
    72					//
    73				document.getElementById("tx").value = str;
    74			}
    75	
    76			/************/
    77			/* 関数 sub */
    78			/************/
    79			function sub()
    80			{
    81	//			str  += "   sub x " + x + "\n";   // 許されない
    82				let x = 40;
    83				str  += "   sub x " + x + "\n";
    84				str  += "   sub z " + z + "\n";   // グローバル変数
    85				w     = 50;
    86			}
    87		</SCRIPT>
    88	</HEAD>
    89	<BODY  STYLE="font-size:130%">
    90		<P STYLE="text-align:center">
    91			<INPUT TYPE="button" VALUE="OK" onClick="run()" STYLE="font-size:90%"><BR><BR>
    92			<TEXTAREA TYPE="text" ID="tx" COLS="30" ROWS="10" STYLE="font-size: 100%"></TEXTAREA>
    93		</P>
    94	</BODY>
    95	</HTML>
    			
      基本的に,ブロック内( { } で囲まれた部分,関数も含む)で,let を指定して定義すると,ブロック内のその変数が定義された以降で有効になります.また,関数内で,var を指定して定義すると,たとえブロック内で定義したとしても,関数内のその変数が定義された以降で有効になります.これらの変数をローカル変数と呼びます.関数外で定義された変数,または,let や var を付加せずに定義された変数は,グローバル変数と呼ばれ,変数が定義された以降であれば,どこからでも参照可能(有効)になります.ただし,C/C++ や Java の有効範囲とはかなり異なっていますので注意してください.上のプログラム例について説明する前に,プログラムの断片によって,いくつかの確認を行っておきます.

      まず,var について考えてみます.下に示すプログラムの断片において,01 行目の x は,関数外で定義されたグローバル変数です.しかし,03 行目では,01 行目の x は無視され,「 undefined 」が出力されます.確かに,var を使用して定義された変数の有効範囲は定義された以降ですが,その影響は定義されたブロック全体に及び,関数の外側で定義された同じ名前の変数は無視されます.この例の場合は,04 行目の変数 x の定義が,03 行目に影響を与えています(宣言の巻き上がり).また,var に関しては,04 行目,06 行目のように,複数回定義しても許されますが,08 行目の定義は許されません.
    01	x = 10;
    02	function run() {
    03		alert(x);   // undefined
    04		var x = 20;
    05		alert(x);
    06		var x = 30;
    07		alert(x);
    08	//	let x = 40;  // 定義済みエラー
    09		・・・・・
    10	}				
      次に,let について考えてみます.グローバル変数や影響範囲に対する考え方は var の場合と同じですが,下に示すプログラムの断片において,03 行目では,未定義のためエラーになってしまいます.この例の場合も,04 行目の変数 x の定義が,03 行目に影響を与えています(宣言の巻き上がり).また,複数回同じ名前の変数を定義することは許されません.
    01	x = 10;
    02	function run() {
    03	//	alert(x);   // 未定義エラー
    04		let x = 20;
    05		alert(x);
    06	//	let x = 30;  // 定義済みエラー
    07	//	var x = 30;  // 定義済みエラー
    08	}				
      関数内において,同じ名前の変数を var や let を付加して定義しなければ,下に示すプログラムの断片における 01 行目のグローバル変数が有効になります.
    01	x = 10;
    02	function run() {
    03		alert(x);
    04		x = 20;
    05		alert(x);
    06	}				
      では,上の枠内に示したプログラム例についての説明に移ります.まず,32 行目において,let を付加して変数 x が定義され(変数 x に値が代入され),10 で初期設定されています.この変数 x は,この位置から run 関数が終わる 73 行目まで有効になります.以下,この関数内の 51 行目,61 行目に対応する結果は,32 行目で宣言されたときの値になります.ただし,32 行目の変数の値が 5 以下の時は,53 行目の代入文のため,54 行目,61 行目の文によって,変数 x の値として -15 が出力されます.また,関数 sub 内の x は,関数 run 内の x とは全く別の変数ですので,81 行目は変数 x が未定義のためエラーになります.

      32 行目のように,let を付加して定義された変数の有効範囲内では,同じ名前の変数を再定義することはできません( 56 行目).33 行目において var を付加して定義された変数 a の有効範囲も,run 関数が終わる 73 行目までになりますが,57 行目のように再定義することが可能です.そして,この行以降は,ここで設定された値が有効になります.

      上で述べましたように,let を付加して定義された変数の有効範囲内では,同じ名前の変数を再定義することはできませんが,その内側のブロックでは,同じ名前の変数を再定義することができます( 37 行目,39 行目).勿論,var を付加して定義された変数においても再定義可能ですが,ただし,その意味はかなり異なってきます.let を付加した変数の場合,その有効範囲はブロックの最後までですが( 37 行目の x は 48 行目まで,39 行目の x は 40 行目まで,43 行目の b は 48 行目まで),var を付加した変数( 42 行目の a,44 行目の y )の有効範囲は関数の終わりまでとなります.しかし,変数 y は,ブロック内で定義されているため,32 行目の変数 x の値が 5 以下の時は,64 行目の文によって,undefined が出力されます.また,36 行目の文によって,33 行目で設定された a の値が問題なく出力されますが,35 行目は,37 行目の定義が存在するため,未定義によるエラーになってしまいます(宣言の巻き上がり).C/C++ のように,35 行目~ 36 行目では,32 行目で定義された変数 x が有効になると考えがちですので,注意してください.

      13,14 行目に定義されている変数 str,z は,let や var が付加されていませんので,グローバル変数となり,どの関数からも参照可能になります.85 行目に定義されている変数 w も,let や var が付加されていませんので,グローバル変数となります.しかし,58 行目の段階では,まだ関数 sub が呼ばれていませんので,変数 w が未定義のためエラーになります.このような定義方法は非常に紛らわしく,誤りの原因になりかねません.「関数内で使用するローカル変数には必ず let (場合によっては,var )を付加し,グローバル変数は関数外で let や var を付加せずに宣言する」といった規則を守った方が良いと思います.また,ブロック内において,その外側で定義された変数と同じ名前の変数は使用しない方が良いと思います.

      以上,このプログラムを実行すると,64 行目までの文によって,以下に示すような出力が得られます.各行に付加した数字は,対応する文番号です
    		// 32 行目の x が 10 のとき
    35	then block a 100
    39	then block block x 20
    44	then block x 15
    45	then block a 200
    46	then block b -100
    47	then block y 20
    82	   sub x 40
    83	   sub z 30
    59	w 50
    60	x 10
    61	a 200
    63	y 20
    		// 32 行目の x が 1 のとき
    50	else block x 1
    51	else block a 100
    53	else block x -15
    82	   sub x 40
    83	   sub z 30
    59	w 50
    60	x -15
    61	a 100
    63	y undefined				
      次に,オブジェクトについて考えてみます.16 ~ 25 行目において新しいオブジェクトを定義しています.23 ~ 25 行目は,C++ におけるメンバー関数の定義に対応します.オブジェクト内の変数や関数は,すべて public であり,どこからでも参照可能です.なお,クラスに関してもほとんど同じです.上のプログラムにおいて,19,20,23 行目を,コメントのように変更し,かつ,21 行目を 25 行目の後ろに移動すれば,クラスを利用したプログラムになります.勿論,「クラスと継承」において説明したように,クラスの場合は,プロパティやメソッドの前に # を付加することによって,クラスの外部から参照できなくすることが可能です.

      67 行目において,オブジェクト Example のインスタンス ex を生成し,68 行目では,オブジェクト Example 内の関数 sub を通して,変数 x を出力しています.69 行目は,オブジェクトの外から,直接に,変数 x の値を出力した場合です.オブジェクト内の変数や関数は,すべてどこからでも参照可能ですが,「 ex. 」のような部分を付加しなければならず,プログラムの他の部分で同じ名前の変数や関数を使用していてもそれらと識別でき,混乱を防ぐことができます.これが,オブジェクトを使用する最大の利点かもしれません.以上,67 ~ 69 行目内の文によって,以下に示すような出力が得られます.
    sub member( x ) 1000
    member( x ) 1000				

情報学部 菅沼ホーム 目次 索引