##はじめに
JavaScriptの基礎をある程度終え、次の開発環境がReactをTypeScriptで書くということだったので一通り学んでみました。
今回は羽山 博さんのTypeScriptで学ぶJavaScript入門を参考にしてまとめました。文章やコードはサイトから引用したものになります。2014年から2015年に連載されたものなので情報が古い点があるかもしれません。プログラミング初学者向けに書かれた記事だったので大変わかりやすかったです。
詳しい内容などは、サイトを参考にしてください。全部まとめたので結構長いです。
3、4日かけて読みました。
##TypeScriptとは
・マイクロソフトが開発したスクリプト言語である。
・オープンソースである。
・TypeScriptのソースコードはJavaScriptのソースコードにコンパイルされる。
###JavaScriptから追加された点
・変数のデータ型をあらかじめ決めておける(静的型付け)。
・クラスを簡単に記述できる。
・1つの関数定義で異なるデータ型の引数を処理できる(総称型)。
・引数の文字列によって異なる関数を実行できる(文字列によるオーバーロード)。
##ここからTypeScripについてまとめていきます
#変数について
###TypeScriptの変数の特徴
・変数を使う前には宣言が必要である。
・変数の宣言時には変数の名前を指定する必要がある。
・変数の宣言時には変数のデータ型が指定できる。
JavaScriptでは特に宣言をせずに、変数がつかえる。しかし、TypeScriptでは変数の宣言が必須である。
###データ型を指定して変数を宣言する
TypeScriptでは、変数の宣言時にデータ型が指定できる。データ型は変数名の後に「:」で区切ってしてする。
・データ型の指定
var price:number;
・データ型を指定した変数宣言と値の代入
var price:number = 1200;
・同じ型の複数の変数を一度に宣言
var x, y:number;
・異なるデータ型の変数を一度に宣言
var name:string, age:number;
TypeScriptでよく使われるデータ型について
・number型・・・数値(整数, 浮動小数点)
・string型・・・文字列
・boolean・・・真偽値(trueまたはfalse)
・enum・・・列挙型
変数のデータ型を指定しない場合は、「any」が指定されたものとする。
・型指定のない変数宣言とany型の変数宣言(以下の2つはほぼ同義)
var something;
var something:any;
anyは既存のJavaScriptのライブラリを利用するときに、互換性を維持するために使われる。型が決まっている場合は、anyではなく、numberやstringを使ったほうがよい。
TypeScriptでは宣言時に変数の値を代入(初期化)しておくと、変数のデータ型が自動的に推測されて決められる。
・データ型を指定せずに変数の宣言を行い初期値も代入する
var price = 1200
この場合、price変数は数値を代入したためnumber型とみなされる。したがって、次の2つのコードのうち上はエラーとならないが、下はエラーとなる。
・データ型を書かないとany型とみなされる
var price; //any型 price = 1200; price = "無料"; //文字列も入力できる
・データ型を書いていないが、数値が初期化しているのでnumber型とみなされる
var price = 1200; //number型と推測される price = "無料"; //文字列を代入しようとするとエラーになる
#####変数のデータ型と代入されるデータ型が一致していない例
var price:number = 1,200;
->数値の表記に桁区切りのカンマは使えない
var price:number = "1200";
->「1200」を引用符で囲んでいるので、数値ではなく文字列とみなされる。
var customerId:string = 100;
->数値を文字列型の変数に代入しようとしているためエラー。
var isAbsent:boolean = "true";
->データ型が真偽値の変数なので「true」の文字列を代入しようとしたためエラー。
var isAbsent:string = true;
->文字列型の変数に真偽値を代入しようとしているためエラー。
#リテラルと列挙型
###決まった値を表すリテラル
リテラルとは決まった値のことをさす。真偽値を表すtrueやfalseもリテラルである。
・整数値リテラルには、10進数、16進数、8進数がある。
(例)
1200 -3 0x1F //16進数の1F。10進数なら31 012 //8進数の12。10進数なら10。だたし8進数の表記はTypeScriptではエラーになる
・浮動小数点リテラルは、小数点うあ指数表記を使った数値である。
(例)
3.14 0.12e+4 //0.12×10の4乗を表す -2.178E-3 //-2.178x10の-3乗を表す
・文字列リテラルは引用符に囲まれた文字列である。シングルクォーテーション(')も使用できる。
(例)
"Hello" "こんにちは" "100"
・ブール型のリテラルには、trueまたはfalseがある。
###種類を区別するのに便利な列挙型 (enum)型
「enum」とは「enumurate」の略で、「列挙する」という意味になる。
・季節を表示するプログラム
enum SEASONS{SPRING, SUMMER, AUTUMN, WINTER}; alert(SEASONS.AUTUMN) //=> 2
「enum」というキーワードの後に好きな名前を指定し、「{}」の中に要素をかく。通常の変数やリテラルと区別できるように、ここでは大文字で書いている。
列挙型の名前は変数の宣言に使用できる。というより、変数を宣言してこそ意味がある。
・列挙型の変数の宣言
var season:SEASONS
ここでは「:」で区切ってデータ型にenum型の名前を指定している。
#演算と演算子
###注意点
・算術演算子は、0で除算することは許されないため「infinity(無限大)」になる。
・0/0の場合は、NaNとなる。
(Not a Number=数値でない値。不正な値を利用して数値演算が行われたことを表す値)
###演算子の結合方向に注意
・結合方向とは
同じ優先順位の演算が実行される順序のこと。
・代入演算子の結合方向を確認するプログラム
var a, b: number; b = 10; a = b +=2; // 「b += 2」が実行された後、「a = b」が実行される alert("aの値は" + a + "\nbの値は" + b);
・インクリメント(加算。「++」)とデクリメント(「--」)の演算子には、結合方向が示されない。理由は、複数個使われないため。
.次のプログラムは実行すると「0」という結果が表示される。ただし、変数countは1になる。
var count:number; count = 0; alert(count++);
「++」を変数名の前につけると、変数の値が増やされ、その増やされた値が返される。(前置型)しかし、「++」を変数名の後につけると、変数の値を増やされるが、返される値は増やされる前の値である。(後値型)
#条件分岐
##条件分岐の特徴
###・if...else文 (式の値によって異なる文を実行する。if文を組み合わせ、異なる変数の値を調べて条件分岐させることもできる。
//午後であるか午前であるかによって、背景色をかえるプログラム
var c: string;
var h: number, d:Date; //Dateオブジェクトの作成
d = new Date();
h = d.getHours(); //getHoursメソッドで時刻を求める
if (h < 12){
c = "skyblue";
} else {
c = "lightyellow";
}
document.body.style.backgroundColor = c; //色の名前を背景色にする
###・if...else文のネスト (if..else文の中にif...else文をかくことをネストまたは入れ子と呼ぶ)
var message: string;
var age, sex: number;
enum SEX { MALE, FEMALE };
sex = SEX.FEMALE; //女性とする
age = 17;
if (sex == SEX.MALE) {
if (age >= 18) {
message = "結婚できます";
} else {
message = "まだ結婚できません";
}
} else {
if (age >= 16) {
message = "結婚できます";
} else {
message = "まだ結婚できません";
}
}
alert(message);
//=>結婚できます
###条件式の書き方
if(425 < rbc < 570) //誤った書き方
if(rbc > 425 && rbc < 570) //正しい書き方
誤った書き方では、「425 < rbc」の結果がtrueまたはfalseになってしまう。よって、次の比較が「true < 570」や「false < 570」になってしまい条件が常に成り立ってしまうため。ただし、TypeScriptでは、変数の型をチェックすルため誤った書き方をするとコンパイルエラーとなる。
##switch文による多分岐
if文は汎用的な条件分岐の構文だが、switch文は1つの変数や式が特定の値であるかどうかを判定して多分岐させるときに便利な構文である。
//おみくじプログラム
var fortune: string;
var n: number;
n = Math.floor(Math.random() * 7); //0~6までの整数の乱数.floorメソッドで小数点以下を切り下げ.
switch (n) {
case 0:
case 1:
fortune = "大吉"; //0と1の場合
break;
case 2:
fortune = "中吉";
break;
case 3:
case 4:
fortune = "小吉";
break;
case 5:
fortune = "凶";
break;
default:
fortune = "大凶"; //上記以外の場合
}
alert(n + ":" + fortune);
switch文のポイント
・switchの後の()の中の変数や式の値によって実行する文が変えられる
・()の中の変数や式の値がcaseの後に指定した値に一致すれば、それ以降の文が全て実行される
・1つのcaseの中に複数の文を書いてもよい
・ただし、break文があると、そこでswitch文を抜けて次の文に進む
・dafaultは他のcaseで指定していない全ての値に一致する
注意すべき点
一致した箇所の文だけが実行されるのではないため、一致した箇所の文だけを実行したいときには、その部分の最後にbreakをかく必要がある
##?演算子 (条件演算子)
?演算子を使うと、条件によって利用する式が変えられる。変数に代入する値を条件によって変えるときに便利な式である。
//割引額を表示するプログラム
var discount: number; //割引金額
var price: number = 1000; //1000円の商品
var rank: string = "gold"; //顧客ランク(goldランクとする)
//goldなら2割引,それ以外なら1割引
discount = (rank == "gold" ? price * 0.2 : price * 0.1);
//tureであれば:の前の値を返す.falseであれば:の後ろの値を返す
alert(discount);
//ネストさせる場合
discount = (rank == "gold" ? price * 0.2 : (rank == "silver" ? price * 0.15 : price * 0.1));
###?演算子の構文 [ 式1 ? 式2 : 式3 ]
条件が多くなる場合は可読性が悪くなるのでif...else文かswitch文を使ったほうがいい。
#繰り返し処理 : while/do...while文
##繰り返し処理の方法
条件を満たしている間、同じ構文を繰り返して実行したり、一定の回数だけ文を繰り返し実行したりするときに使用する。
・while文...式の値がtrueである間、文を繰り返し実行する、式の値を毎回の繰り返しの前に判定する(全判定型while)
・do ... while文...式の値がtrueである間、文を繰り返し実行する。式の値をマイカの繰り返しの後に判定する(後判定型while)
・for文...初期設定、繰り返しの条件、毎回の繰り返しの後に実行する処理をまとめてかける文。一定回数の繰り返し処理によく使われる
・for...in文オブジェクトの全てのプロパティの値に対して繰り返し処理を行う
###while文を使った例
//6が出るまでに何回サイコロを振ったかがわかるプログラム
var count: number = 0;
var dice: number;
dice = Math.floor(Math.random() * 6) + 1;
while (dice != 6) {
count++;
dice = Math.floor(Math.random() * 6) + 1;
}
alert(count);
注意点
while文では、条件として指定する式がtureの間、文を繰り返し実行するので、式がfalseにならない限り無限に繰り返される。これを無限ループという。
while文を簡潔にかく
//function文を使って関数を作成し、プログラムを簡潔にする
var count: number = 0;
while (dice() != 6) { //dice関数を呼び出して、乱数を求める
count++;
}
alert(count);
window.close();
function dice(): number { //関数が返す値のデータ型の指定
return Math.floor(Math.random() * 6) + 1;
}
###do...whileを使った例
do...while文では、条件を判定するための式を毎回の繰り返しの後に評価する。この場合、繰り返し処理は最低でも1回は実行される。
//6が出るまでに何回サイコロを振ったかがわかるプログラム
var count: number = 0;
var dice: number;
do {
dice = Math.floor(Math.random() * 6) + 1;
count++;
} while (dice != 6);
alert(count);
###繰り返しを途中で抜けるには
//1が出た時点でゲームオーバーとするプログラム
var count: number = 0;
var d: number;
while ((d = dice()) != 6) {
if (d == 1) { // (2)
alert("NGな目が出ました");
break; // 1が出たらその時点でおしまい
}
count++;
}
alert(count);
window.close();
function dice(): number {
return Math.floor(Math.random() * 6) + 1;
}
###次の繰り返しに即座に移る
break文のように繰り返しを完全に抜けるのではなく、その時点で後ろの処理を実行せずに次の繰り返しに移るにはcontinue文を使う。
//同じ目が連続して出た時は1回と数えるプログラム
var count: number = 0;
var d: number;
var prev: number = 0; //最初はありえない値
var dup: number = 0; //重複した回数
while ((d = dice()) !=6) {
if (prev == d) {
dup++;
continue; //前回と同じなら数えない
}
count++;
prev = d; //今回の値を保持しておく
}
alert(count + ":" + dup);
function dice(): number {
return Math.floor(Math.random() * 6) + 1;
}
##for文を使った例
//「ピザ」という文字を10回表示する
for (var i = 0; i < 10; i++) {
document.body.innerHTML += "ピザ<br/>";
}
//データ型を指定していないが、ここでは初期値によってデータ型が推測されている
###for文の書き方
for (式1; 式2; 式3) { 文1; 文2; : }
・式1...最初に1回だけ実行される、一般的には、この式で繰り返しの回数を数えるための変数(制御変数)の初期値を設定する。初期化式とも呼ばれる。
・式2...trueかfalseかを返す式を指定する。式2がtrueである間、文が繰り返し実行される。一般的には、制御変数が特定の間より小さい間(大きい間)といった意味の式が書かれる。条件式とも呼ばれる。
・式3...毎回の繰り返しの最後に実行される。一般的には、制御変数の値を変える式が書かれる。再初期化式とも呼ばれる。
###for文をネストさせる
//10行10列の「.]を表すプログラム
document.body.style.fontFamily = "Courier","monospace";
for (var i = 0; i < 10; i++) {
for (var j = 0; j < 10; j++) {
document.body.innerHTML += ".";
}
document.bodyHTML += "<br/>";
}
//10列×10行の「.」のランダムな位置にモンスターを表示するプログラム
var m_name: string = "D";
var x: number = Math.floor(Math.random() * 10);
var y: number = Math.floor(Math.random() * 10);
document.body.style.fontFamily = "Courier","monospace";
for (var i = 0; i < 10; i++) {
for (var j = 0; j < 10; j++) {
if (i==y && i==x) {
document.body.innerHTML += m_name;
} else {
document.body.innerHTML += ".";
}
}
}
document.body.innerHTML += "<br/>";
}
###for...in文
for...in文はオブジェクトのプロパティ名を1つずつ取り出して順に処理していく。そして、取り出すプロパティ名がなくなると繰り返し終了となる。
//モンスターのステータスを表示するプログラム
class Monster { //クラスを定義
name: string;
hp: number;
mp: number;
}
var m: Monster = new Monster(); //クラスからオブジェクトを作成
m.name = "Dragon";
m.mp = 100;
m.mp = 200;
document.body.innerHTML = "モンスターのステータス一覧<br/>";
for (var x in m) {
document.body.innerHTML += x + ":" + [x] + "<br/>";
}
#配列
##配列とは
多数の変数を利用できるようにする仕組みが配列である。配列を宣言するには、全ての要素を代表するような変数名を一つつけておけばよい。配列の個々の要素はインデックスと呼ばれる番号で区別する。配列と似た連想配列がるが、これはインデックスとしての数値だけでなく文字列も使用できるものである。
###簡単な配列の例
//五人囃子のうち、左から3番目の楽器の名前を取り出して表示するプログラム
var musicians: string[] = new Array(5);
musicians[0] = "たいこ";
musicians[1] = "おおづつみ";
musicians[2] = "こづつみ";
musicians[3] = "ふえ";
musicians[4] = "うたい";
alert(musicians[2]); //=>こづつみ
//ポイント
//・変数を宣言するときにデータ型の後ろに[]をつける
//・new Arrayの後ろに()をかき、その中に要素数をかく
・配列を宣言する別の書き方
var musicians: Array<string> = new Array(5);
###配列の宣言と初期化を一度に行う
var musicians: string[] = ["たいこ", "おおづつみ" ,"こづづみ" ,"ふえ" ,"うたい"];
この書き方では,new演算子を使う必要がないのでコードが簡単になる。
・配列の宣言と初期化の別の書き方
var musicians: Array<string> = ["たいこ", "おおつづみ", "こつづみ", "ふえ", "うたい"];
配列の注意点
要素数を指定して配列の宣言をしても、配列には後から要素を追加できる。また、配列のインデックスは0から並んでいるとは限らない。lengthプロパティで取得できる値は配列の要素数を表している訳ではない。
//配列のインデックスが連続でないことや、要素を追加できることを確認するためのプログラム
var a:Array<number> = new Array(3);
a[0] = 0;
a[1] = 10;
a[10] = 100;
a[20] = 200;
alert("2番目は" + a[2] + ",10番目は" + a[10] + ",配列のサイズは" + a.length);
//=> 2番はundefined、10番は100、配列のサイズは21
//lengthプロパティの値は「インデックスの最大値+1」になるため
//配列の要素数を知るためにはObjectのkeysメソッドを使う
alert( "配列のサイズは" + Object.keys(a).length );
###配列の繰り返し処理
//10個の要素と持つ配列を使って、0〜9の数値をランダムに並び替えるプログラム
var board: Array<number> = new Array(10);
var temp, r1, r2: number;
for (var i = 0; i < 10; i++) { //変数iの値が0から10未満である間、値を1ずつ増やしながら処理を繰り返す
board[i] = i; //board[0]~board[9]には0~9が代入
}
for (var count = 0; count < 100; count++) {
r1 = Math.floor(Math.random() * 10)
r2 = Math.floor(Math.random() * 10)
temp = board[r1] = board[r2];
board[r2] = temp;
}
alert(board);
###2次元の配列を利用する
TypeScriptで2次元の配列を宣言するには、[]を2つ書けばよい。
//2次元の配列を作成して、連番を入れるプログラム
var board: number[][] = new Array();
for (var i = 0; i < 9; i++) {
board[i] = new Array();
for (var j = 0; j < 9; j++) {
board[i][j] = i * 9 + (j + 1);
}
}
alert(board);
##連想配列
連想配列はインデックスとして数値だけでなく文字列を使用できる。連想配列を利用する2つの方法。
・オブジェクトリテラルを使ってオブジェクトを作成し、プロパティを追加して連想配列のように扱う。
・Arrayオブジェクトを作成して、配列のインデックスに文字列を指定する。
###オブジェクトリテラルを使って連想配列を作る
オブジェクトリテラルとは、オブジェクトに含まれる要素を{}で囲んで記したもの。
//守備位置と名前の連絡配列から、投手の名前を取り出して表示する
var Player = {Pitcher: "岩田", Catcher: "梅野"}; //Playerという名前のObject型変数の宣言
alert(Player["Pitcher"];
//インデックスは文字列だが、引用符で囲んでも囲まなくてもよい。
//だが、インデックスが数字で始まる場合や、途中にスペースを含む場合は引用符で囲む必要がある。
var Player = { Pitcher: "岩田", Catcher: "梅野", "1st": "ゴメス",
"2nd": "上本", "short stop": "鳥谷" };
オブジェクトとは、関連性を持ったさまざまなデータや手続きをまとめて取り扱うためのものである
上のように作成したオブジェクトは汎用的なオブジェクトであり、必要に応じて、数値や文字列、関数などを含めることができる。ここでは、Object型のオブジェクトを基として作られる。
###連想配列に要素を追加する
新しいインデックスを指定すれば、連想配列の要素は自由に追加できる
//連想配列に要素を追加する
var Player = new Object(); //new演算子を使って新しいオブジェクトを作成し、後から要素を追加する
Player["Pitcher"] = "岩田";
Player["Catcher"] = "梅野";
alert(Player["Pitcher"]);
//空のオブジェクトリテラルを使ってオブジェクトを作成
var Player = {};
###JavaScriptとの違い
JavaScriptでもTypeScriptでも連想配列を作成したら、そこにインデックスと値を追加したり、要素を削除できる。
ただし、JavaScriptではそれらは常にプロパティとしてアクセス可能であるのに対して、TypeScriptでは常にプロパティとしてアクセスできるとは限らない。
//「.」で区切ってプロパティを利用する。このコードはTypeScriptではエラーになる
var Player = {}; //変数Playerの型は「{}」となる.この時に「Pitcher」というプロパティが存在しないのでアクセスエラーとなる
Player["Pitcher"] = "岩田";
alert(Player.Pitcher); //Pitcherプロパティの値を取り出す
Player.Catcher = "梅野"; //Catcherプロパティに値を代入
####連想配列の要素を削除
delte Player["Pitcher"]; //Pitcherというインデックスをもつ要素を削除
##連想配列のすべての要素を取り扱う
連想配列ののインデックスは数値ではないので、for文を使ったり繰り返し処理ができない。そこで、for...in文を使えばオブジェクトのプロパティを全て取り出せるので、それらのプロパティに対する値を求めれば、連想配列の要素を全て処理できる。
//オブジェクトのプロパティ名を全て表示する
var Player = {Pitcher: "岩田", Catcher: "梅野"};
for (var x in Player) {
alert(x); //要素数の数だけアラートボックスが表示される
}
//連想配列の各要素の値を表示したい場合
var Player = {Pitcher: "岩田", Catcher: "梅野"};
var Members: string = "";
for (var x in Player) {
Members + Player[x] + "\n"; //各要素の値を連結して一度に表示できるようにする
}
alert(Members);
###インデックスや要素のデータ型を指定する
TypeScriptではインデックスシグネチャと呼ばれる仕組みによって、インデックスや要素のデータ型を指定できる。
//インデックスシグネチャを指定して、連想配列に含まれる要素のデータ型を指定する
var Player: {[index: string]: string;} = {Pitcher: "岩田", Catcher: "梅野"};
alert(Player["Pitcher"]);
//このようにデータ型を指定しておけば、数値型の値などを代入しようとした場合エラーになる
・インデックスシグネチャの書き方
var Player: {[index: string]: string;} = ...
var Player: {[インデックスのデータ型]: (要素のデータ型);} = ...
となる
インデックスシグネチャーを追加すると、プログラムが読みづらくなるので、interfaceと呼ばれるキーワードを使って、インデックスシグネチャに名前をつけることもできる。
//「interface]の後に、自分で型名をかき、その後にインデックスシグネチャの内容をかく
interface Dictionary {
[index: string]: string;
}
//インデックスシグネチャの部分に型名をかく
var Player: Dictionary = {Pitcher: "岩田", Catcher: "梅野"};
alert(Player["Pitcher"]
##配列のインデックスに文字列を指定する方法
Array型を配列を宣言し、インデックスに文字列を指定して連想配列を作成することができる。
var Player: string[] = new Array(9); //(1)
Player["Pitcher"] = "岩田";
Player["Catcher"] = "梅野";
alert(Player["Pitcher"];
//(1)配列の宣言の別の書き方
var Player: Array<string> = new Array(9);
#関数
関数とはひとまとまりの処理を記述して名前をつけたもの。関数に与える値を引数と呼び、戻り値とは関数が返す処理の結果のことである。戻り値を返り値とも呼ぶ。
関数の利点
・一度関数を書いておけば、内部でどういう処理をしているか詳しく知らなくても利用できる。
・必要な箇所で何度も利用できる。
TypeScriptやJavaScriptの特徴としては関数もオブジェクトであるということだ。
関数の書き方
・関数宣言を使う方法
・関数式を使う方法
・アロー関数式を使う方法
###関数宣言を使う書き方
//2つの数を与えるとその和を返す関数add2の定義と利用
function add2(x: number, y:number): number { //関数add2の定義
return x + y;
}
var answer: number = add2(10, 20); //関数add2を呼び出して、戻り値を変数に代入
alert(answer);
書き方
function 関数名(仮引数の名前: データ型, ...):戻り値のデータ型 { return 戻り値; }
呼び出し方
var answer: number = 関数名(実引数のリスト);
実引数とは、仮引数に与える値のことである
英語では仮引数のことを「parameter」(パラメーター)と呼び、実引数を「argument」と呼ぶ。
###関数式を利用する書き方
関数はオブジェクトであるため、変数にも代入できる
//関数オブジェクトを作成して、変数に参照を代入する
var add2 = function(x: number, y:number): number { //(1)
return x + y;
};
var answer: number = add2(10, 20); //(2)
alert(answer);
//(1)function演算子を使って関数オブジェクトを作成し、その参照を変数add2に代入している
//(2)変数add2に関数を代入しているため、変数add2を利用すれば関数が呼び出せるようになっている
書き方
var 関数を参照する変数の名前 = function (仮引数の名前: データ型, ...): 戻り値のデータ型 { return 戻り値; };
この時変数のデータ型は型推論の機能により、function型になっている。
###アロー関数式を使う書き方
アロー関数あるいはラムダ式と呼ばれる簡潔な書き方だ。
//アロー関数を使って簡潔に関数を定義するプログラム
var add2 = (x:number, y:number): number => x + y;
var answer: number = add2(10, 20);
alert(answer);
###1つの関数で複数の戻り値を返す方法
書き方は1つしか指定できないが、戻り値にオブジェクトを指定すれば、複数の値をまとめて返せる。
//複数の値を返すプログラム
function div2(x: number, y: number) {
var q: number = Math.floor(x/y);
var r: number = x - q * y;
return { quotient: q, reminder: r} //(1)
};
var result = div2(20, 8);
alert("商は" + result.quotient + ",余りは" + result.reminder);
//(1)戻り値のデータ型は複雑になるため、宣言に含めずに推測型を使用している
###オプションの引数
関数を定義するときには、仮引数としてオプションの引数が指定できる。仮引数をオプションとするとその仮引数に対応する実引数を省略することもできるようになる。
function calcCost(price: number, amount: number, discount?: number): number {
if (discount) { //別の書き方 if (discount != undefined)
return price * amount * (1 - discount);
} else {
return price * amount;
}
}
alert(calcCost(1200, 10));
//=> 12000
可変長引数を使う、関数を呼び出すときにコオtなる数のデータを渡せる。
//省略可能な引数と可変長引数
function paramtest(arg1: number, ...restparam: number[])
{
return "first item of restparam: " + restparam[0] +
"\nlength of restparam: " + restparam.length;
}
alert(paramtest(1, 2, 3, 4, 5));
paramtest関数の第一引数(arg1)は省略不可能であり、次のrestparamが可変長引数となっている。可変このデータを受け取る仮引数は「...」に続けてその名前を記述する。この場合仮引数の型は配列型でなければいけない。特に指定しない場合はany[]型になる。「1」が仮引数arg1に、残りの2~5が配列としてrestparamに割り当てられる。
注意点として、省略可能な引数や可変長引数は、指定する順序が決まっているということだ。省略可能な引数は省略できない引数の後に書き、可変長引数がある場合には引数リストの最後に指定する。可変長引数は一つしかかけないことも注意しよう。
###引数の規定値を設定する
省略可能な引数には規定値が設定できる。そのためには、仮引数の名前の後に、「=規定値」を指定すれば良い。その場合、仮引数の名前の後に「?」は必要ない。
//省略可能な引数に規定値を設定する
function calcCost(price: number, amount: number, discount = 0): number { //(1)
return price * amount * (1 - discount);
}
alert(calcCost(1200, 10));
//(1)discountにデータ型が指定されていないが、規定値として0を代入しているので、型推論によりnumber型になる
省略できない引数、省略可能な引数、可変長引数を全て指定した例
//省略不可能な引数、省略可能な引数、可変長引数
function paramtest(arg1: number, arg2: number = 2, restparam: number[] {
return "arg1: " + arg1 +
"\narg2: " + arg2 +
"\nfirst item of restparam: " + restparam[0] +
"\nlength of restparam: " + restparam.length;
}
alert(paramtest(1, undefined, 3, 4, 5));
//引数が省略されている場合は「undefind」と記述する。
###関数のオーバーロード
オーバーロードとは、同じ名前をもち、異なる引数リストや戻り値の型をもつ複数の関数を定義することである。
TypeScriptで、関数をオーバーロードするには、実装なしで引数リストと戻り値の型だけを指定したオーバーロード関数を続けて書き、最後にいずれの形式の関数呼び出しにも対応できるような実装をかく。
function getLength(x: number): number; //(1)
function getLength(x: string): number; //(2)
function getLength(x: any): number {
if (typeof(x) == "string") {
return x.length
} else {
if (x == 0) return 1;
return Math.floor(Math.log(x)/Math.LN10) + 1;
}
}
alert(getLength(123));
//=> 3
(1)と(2)を宣言することで、string型もしくはnumber型以外の引数を指定するとTypeScriptコードのコンパイル時点でエラーになるので、型のチェックができるようになる。
###ジェネリックス
***ジェネリックスとは、データ型を仮に決めておき、実際に使用するデータ型を呼び出し時に変えられるようにする機能で、総称型とも呼ばれる。***ジェネリックスはを利用するとデータ型を関数の呼び出し時に決められるので、似てような処理を異なるデータ型の引数に対して行うことができる。
//ジェネリックスを利用した関数
function parrot<T>(data: T): T { //仮引数や戻り値のデータ型を「T」などの文字で表しておく
var ret: T;
ret = data;
return ret;
}
alert(parrot<number>(100));
//=>100
ジェネリックスを使った関数を呼び出すときには、関数名の後に「<>」を書き、その中に実際にどのデータ型を使用するのかをかけば良い。ジェネリックは、様々なデータ型の引数に対してきめ細かく処理を分けるためではなく、どのデータ型に対しても同じような処理をしたい場合に使うと良い。
###クロージャー
クロージャーとは、関数が定義された環境にある変数を利用できる機能である。このクロージャーはTypeScript独自の機能ではなく、JavaScriptに備わっている機能である。
//クローザーを使ったプログラム
function getSerialNumber() {
var origin = 0;
function countUp(delta: number): number {
return origin += delta;
}
return countUp;
};
var inside = getSerialNumber();
alert(inside(2));
alert(inside(3));
//=>2
//=>5
//無名関数を使ってクロージャーをかく
var countUp = function() {
var origin = 0;
return function (delta: number) {
return origin += delta;
};
} (); //関数の定義の後に()をつけると即時実行関数となり、定義と同時に実行される
alert(countUp(2));
alert(countUp(3));
//=> 2
//=> 5
//アロー関数式を使ってクロージャーをかく
var countUp = (() => {
var origin = 0;
return (delta: number) => {
return origin += dalta;
};
})();
alert(countUp(2));
alert(countUp(3));
#クラスの利用
クラスとは、個々のオブジェクトではなく、オブジェクトのひな形のようなものである。
//クラスを使って猫クラスを表す
class Cat {
length: number;
weight: number;
}
//変数の宣言に使っていたvarは書かなくていい。
クラスの中に含まれる変数はプロパティと呼ばれ、関数はメソッドと呼ばれる。このプロパティとメソッドを合わせてクラスのメンバーと呼ぶ。
###クラスからインスタンスを作成する
クラスはいわばひな型のようなものなので、実際のデータを扱うにはインスタンスを作成する必要がある。
//Catクラスのインスタンスの作成
class Cat {
length: number;
weight: number;
}
var myCat = new Cat(); //インスタンスの作成には、new演算子を使う。
newの後に「クラス名()」とかけば新しいインスタンスが作成できる。
###クラスのメンバーを利用する
「.」で区切ってメンバーをかけば、クラスのメンバーが利用できる。
//クラスの定義から、インスタンスの作成、メンバーの利用まで
class Cat {
length: number;
weight: number;
}
var myCat = new Cat();
myCat.length = 30.5;
myCat.weight = 2,5;
alert("体調は" + myCat.length + "cm, 体重は" + myCat.weight + "kgです");
###クラスのメンバーとしてメソッドを定義する
クラスにメソッドを定義する。
//Catクラスにmeowメソッドとeatメソッドを追加する
class Cat {
length: number;
weight: number;
meow(): string {
return "にゃーん";
}
eat() {
this.length += 0.1;
this.weight += 0.1;
}
}
var myCat = new Cat();
myCat.length = 30.5;
myCat.weight = 2.5;
myCat.eat();
alert("私の猫は" + myCat.meow() + "と鳴き, \n体長は" + myCat.length +
"cm, 体重は" + myCat.weight + "kgです")
###メソッドのオーバーロード
メソッドはオーバーロードできる。
//Catクラスのmeowメソッドをオーバーロードする
class Cat {
length: number;
weight: number;
meow(): string;
meow(s: string): string;
meow(s?: any): string {
if (typeof(s) == "string") {
return s;
} else {
return "にゃーん";
}
}
eat() {
this.length += 0.1;
this.weight += 0.1;
}
}
var myCat = new Cat();
myCat.length = 30.5;
myCat.weight = 2.5;
myCat.eat();
alert("私の猫は" + myCat.meow("ミャオ") + "と鳴き, \n体長は" + myCat.length +
"cm, 体長は" + myCat.weight + "kgです");
###コンストラクター
コンストラクターとは、インスタンスの作成時に自動的に実行されるメソッドで、初期値の設定などに使われる。
コンストラクターを定義するには、constructorという名前の関数をかけばよい。
//コンストラクターを定義する
class Cat {
length: number;
weight: number;
name: string;
constructor() { //constructorの定義
this.name = "名無し";
}
}
var myCat = new Cat(); //自動的にコンストラクターが実行されるので、そのまま名前を表示できる
alert("名前は" + myCat.name + "です");
###コンストラクターのオーバーロード
コンストラクターをオーバーロードさせれば、インスタンス作成時の引数の指定により、動作を変えることができる。
//コンストラクターのオーバーロード
class Cat {
length: number;
weight: number;
name: string;
constructor(s: string);
constructor(s?: string) {
if(typeof(s) == "string") {
this.name = s;
} else {
this.name = "名なし";
}
}
}
var myCat = new Cat("タマ");
var yourCat = new Cat();
alert("私の猫の名前は" + myCat.name + "で、あなたの猫の名前は" + yourCat.name + "です");
###情報の隠蔽
重要な情報をプライベート変数にして、クラスの外から勝手に変更されないことを「情報の隠蔽」と呼ぶ。
//プライベートな変数にアクセスするメソッドを作る
class Cat {
private name: string; //privateを指定して、クラス外からはアクセスできない変数となる。
public setName(s; string) {
this.name = s.slice(0, 8); //0文字目から8文字目の手前までが切り出される
}
public getName(): string {
return this.name;
}
}
var myCat = new Cat();
myCat.setName("じゅげむじゅげむごこうのすりきれねこ");
alert("私の猫の名前は" + myCat.getName() + "です");
変数の宣言やメソッドの定義の前に何も書かなかった場合には、publicが指定されたものとみなされることに注意する。
###クラスの継承とメソッドのオーバーライド
継承とは、元のクラス(親クラス)の機能を全て受け継いだ新しいクラス(子クラス)を定義することでもある。
//Catクラスを継承したTigerクラスを定義する
class Cat {
private name: string;
public setName(s: string) {
this.name = s.slice(0, 8);
}
public getName(): string {
return this.name;
}
public meow(): string {
return "にゃーん";
}
}
class Tiger extends Cat {
public meow(): string {
return "がおー";
}
}
var myTiger = new Tiger();
myTiger.setName("とらお");
alert("私の虎の名前は" + myTiger.getName() + "で, " + myTiger.meow() + "と鳴きます");
クラスを継承するには、新しいクラスの名前の後にextendsというキーワードを書き、その後に親クラスの名前をかけば良い。親クラスにある機能が子クラスでは異なる働きをすることもある。このように、親クラスのメソッドを子クラスで定義し直すことを、オーバーライドと呼ぶ。
親クラスのメソッドを呼び出したいときには、メソッドの名前にsuperをつければ良い。
class Cat {
private name: string;
public setName(s: string) {
this.name = s.slice(0, 8);
}
public getName(): string {
return this.name
}
public meow(): string {
return "にゃーん";
}
}
class Tiger extends Cat {
public meow(): string {
return "がおー";
}
public meowlikecat(): string {
return super.meow();
}
}
var myTiger = new Tiger();
myTiger.setName("とらお");
alert("私の虎の名前は" + myTiger.getName() + "ですが、甘えてくるとには" + myTiger.meowlikecat() + "と鳴きます";
###あとがき
修正点など、間違いがございましたら、ご指摘ください。