034.2 レッスン 1
Certificate: |
Web開発の要点 |
---|---|
Version: |
1.0 |
Topic: |
034 JavaScriptプログラミング |
Objective: |
034.2 JavaScriptデータ構造 |
Lesson: |
1 of 1 |
はじめに
プログラミング言語は、自然言語と同様に、現実を記号で表し、それを組み合わせて意味のある文を作ります。プログラミング言語が表現する現実とは、プロセッサの動作、デバイス、メモリなどのマシンのリソースです。
無数に存在するプログラミング言語は、それぞれ情報を表現するためのパラダイムを採用しています。JavaScriptは高水準言語の典型的な慣習を採用しており、メモリの割り当てなどの詳細のほとんどが暗黙の了解となっているため、プログラマはアプリケーションのコンテキストにおけるスクリプトの目的に集中することができます。
高水準言語
高水準言語は、抽象的なルールを提供することで、プログラマがアイデアを表現するために必要なコードを少なくすることができます。JavaScriptは、コンピュータのメモリを便利に利用する方法を提供します。プログラミングの概念を使用することで、反復練習の記述が簡単になり、Web開発者の目的には一般的に十分なものとなります。
Note
|
緻密なメモリアクセスのためには、専用のメカニズムを使うことも可能ですが、ここで紹介するシンプルなデータの種類は、より一般的な使い方になります。 |
Webアプリケーションにおける典型的な操作は、何らかのJavaScriptの命令によってデータを要求し、それを保存して処理し、最終的にユーザーに提示するというものです。この保存は、JavaScriptでは非常に柔軟で、目的に応じて適切な保存形式が用意されています。
定数と変数の宣言
データを保持するための定数や変数の宣言は、あらゆるプログラミング言語の基礎となるものです。JavaScriptでは、ほとんどのプログラミング言語で採用されている name = value
という構文で定数や変数に値を割り当てます。左側の定数または変数は、右側の値を受け取ります。定数または変数の名前は、アルファベットまたはアンダースコアで始めなければなりません。
JavaScriptは、 動的型付け 言語なので、変数に格納されているデータの型を示す必要はありません。変数の型は、変数に代入された値から推測されます。しかし、期待される結果を保証するためには、宣言で特定の属性を指定しておくと便利です。
Note
|
TypeScriptは、JavaScriptにインスパイアされた言語で、低水準言語と同様に、特定のタイプのデータ用に変数を宣言することができます。 |
定数
定数とは、プログラムの起動時に一度だけ割り当てられ、変更されることのない記号のことです。定数は、定数 PI
を3.14159265と定義したり、 COMPANY_NAME
に会社名を入れたりするなど、固定値を指定するのに便利です。
例えば、Webアプリケーションで、リモートサーバから天気情報を受信するクライアントがあるとします。プログラマは、アプリケーションの実行中に変更されることはないので、サーバへのアドレスは一定でなければならないと決めるかもしれません。しかし、温度情報は、サーバから新しいデータが届くたびに変化する可能性があります。
また、サーバへの問い合わせの間隔を定数として定義することもでき、プログラムのどの部分からでも問い合わせが可能です。
const update_interval = 10;
function setup_app(){
console.log("Update every " + update_interval + "minutes");
}
setup_app()
関数を起動すると、コンソールに Update every 10 minutes
というメッセージが表示されます。名前 update_interval
の前に置かれた用語 const
は、スクリプトの実行中ずっとその値が同じであることを保証します。定数の値をリセットしようとすると、 TypeError: Assignment to constant variable
エラーが発生します。
変数
const
という用語がなければ、JavaScriptは自動的に update_interval
が変数であり、その値が変更可能であるとみなします。これは、 var
で明示的に変数を宣言したのと同じです。
var update_interval;
update_interval = 10;
function setup_app(){
console.log("Update every " + update_interval + "minutes");
}
update_interval
変数は、関数の外で定義されていますが、関数内からアクセスされていることに注意してください。中括弧( {}
)で定義された関数やコードブロックの外側で宣言された定数や変数は、 グローバルスコープ を持ちます。つまり、コードのどの部分からでもアクセスできます。逆に、関数の内部で宣言された定数や変数は、 ローカルスコープ であり、その関数の内部からしかアクセスできません。 if
判定構造や for
ループの中にあるような、ブラケットで区切られたコードブロックは、定数のスコープを区切りますが、 var
として宣言された変数のスコープは区切りません。例えば、次のようなコードは有効です。
var success = true;
if ( success == true )
{
var message = "Transaction succeeded";
var retry = 0;
}
else
{
var message = "Transaction failed";
var retry = 1;
}
console.log(message);
console.log(message)
ステートメントは、 if
構造のコードブロック内で宣言されているにもかかわらず、 message
変数にアクセスすることができます。次の例のように、 message
が定数であれば、同じことは起こりません。
var success = true;
if ( success == true )
{
const message = "Transaction succeeded";
var retry = 0;
}
else
{
const message = "Transaction failed";
var retry = 1;
}
console.log(message);
この場合、 ReferenceError: message is not defined
というタイプのエラーメッセージが発行され、スクリプトが停止します。制限があるように見えるかもしれませんが、変数や定数のスコープを制限することで、スクリプト本体と各コードブロックで処理される情報が混同されるのを防ぐことができます。このような理由から、 var
ではなく let
で宣言された変数も、中括弧で区切られたブロックによってスコープが制限されます。変数を var
で宣言するか let
で宣言するかの微妙な違いは他にもありますが、その中でも最も重要なのは、ここで説明するように、変数のスコープに関するものです。
値のタイプ
ほとんどの場合、プログラマは変数に格納されているデータの型を気にする必要はありません。なぜなら、JavaScriptは変数に値を最初に代入する際に、自動的に プリミティブ 型のいずれかで識別するからです。しかし、いくつかの操作は、あるデータ型に固有のものであり、無分別に使用するとエラーになることがあります。また、JavaScriptには、複数のプリミティブ型を1つのオブジェクトにまとめることができる 構造 型が用意されています。
プリミティブ型
プリミティブ型のインスタンスは、1つの値しか格納できない伝統的な変数に相当します。型は暗黙的に定義されているので、 typeof
演算子を使って、変数に格納されている値の型を特定することができます。
console.log("Undefined variables are of type", typeof variable);
{
let variable = true;
console.log("Value `true` is of type " + typeof variable);
}
{
let variable = 3.14159265;
console.log("Value `3.14159265` is of type " + typeof variable);
}
{
let variable = "Text content";
console.log("Value `Text content` is of type " + typeof variable);
}
{
let variable = Symbol();
console.log("A symbol is of type " + typeof variable);
}
このスクリプトは、それぞれのケースでどのようなタイプの変数が使用されたかをコンソール上に表示します。
undefined variables are of type undefined Value `true` is of type boolean Value `3.114159265` is of type number Value `Text content` is of type string A symbol is of type symbol
最初の行は、宣言されていない変数の型を見つけようとしていることに気をつけて下さい。これにより、指定された変数は「未定義」であると見なされます。`symbol`型は、最も直感的ではないプリミティブです。その目的は、属性名を定義する必要がない場合に、オブジェクト内にユニークな属性名を提供することです。オブジェクトとは、データ構造の一種で次に説明します。
構造型
プリミティブ型は、簡単なルーチンを書くのには十分ですが、複雑なアプリケーションでは、プリミティブ型ばかりを使うことには欠点があります。例えば、E-コマースのアプリケーションでは、プリミティブ型の変数だけを使って、アイテムのリストとそれに対応する値を格納する方法を見つけなければならないので、書くのが非常に難しくなります。
構造型は、同じ性質の情報を1つの変数にまとめる作業を簡単にします。例えば、ショッピングカートに入っている商品のリストは、 配列 型の1つの変数に格納することができます。
let cart = ['Milk', 'Bread', 'Eggs'];
この例では、項目の配列を角括弧で囲んでいます。この例では、配列に3つのリテラル文字列値を入力しているため、一重引用符を使用しています。変数を配列の項目として使用することもできますが、その場合は引用符を使用せずに指定する必要があります。配列のアイテムの数は、 length
プロパティで調べることができます。
let cart = ['Milk', 'Bread', 'Eggs'];
console.log(cart.length);
コンソール出力には、数字の 3
が表示されます。配列に新しいアイテムを追加するには、 push()
メソッドを使用します。
cart.push('Candy');
console.log(cart.length);
今回、表示される金額は 4
となります。リストの各項目は、 0
から始まる数値インデックスでアクセスできます。
console.log(cart[0]);
console.log(cart[3]);
コンソールに表示される出力は次のようになります。
Milk Candy
push()
で要素を追加するのと同じように、 pop()
で配列から最後の要素を削除することができます。
配列に格納される値は、同じ型である必要はありません。例えば、各アイテムの横に数量を格納することも可能です。先ほどの例のような買い物リストは、次のように作ることができます。
let cart = ['Milk', 1, 'Bread', 4, 'Eggs', 12, 'Candy', 2];
// Item indexes are even
let item = 2;
// Quantities indexes are odd
let quantity = 3;
console.log("Item: " + cart[item]);
console.log("Quantity: " + cart[quantity]);
このコードを実行した後にコンソールに表示される出力は次のとおりです。
Item: Bread Quantity: 4
すでにお気づきかもしれませんが、アイテムの名前とそれぞれの数量を1つの配列にまとめることは、良いアイデアではないかもしれません。なぜなら、それらの関係はデータ構造の中で明示されておらず、(人為的な)エラーの影響を非常に受けやすいからです。名前に配列を使い、数量に別の配列を使ったとしても、リストの整合性を維持するには同じような注意が必要で、あまり生産的ではありません。このような状況では、より適切なデータ構造である オブジェクト を使用するのが最善の方法です。
JavaScriptでは、オブジェクト型のデータ構造により、変数にプロパティをバインドすることができます。また、配列とは異なり、オブジェクトを構成する要素の順序は固定されていません。例えば、ショッピングリストのアイテムは、 name
と quantity
というプロパティを持つオブジェクトになります。
let item = { name: 'Milk', quantity: 1 };
console.log("Item: " + item.name);
console.log("Quantity: " + item.quantity);
この例では、中括弧( {}
)を使ってオブジェクトを定義し、各プロパティと値のペアをコロンで区切り、プロパティをカンマで区切っています。プロパティは item.name
のように variable.property という形式でアクセスでき、読み取ることも、新しい値を代入することもできます。このコードの実行後にコンソールに表示される出力は次のとおりです。
Item: Milk Quantity: 1
最後に、アイテムを表す各オブジェクトをショッピングリストの配列に含めることができます。これは、リストを作成する際に直接行うことができます。
let cart = [{ name: 'Milk', quantity: 1 }, { name: 'Bread', quantity: 4 }];
先ほどと同様に、アイテムを表す新しいオブジェクトを後から配列に追加することができます。
cart.push({ name: 'Eggs', quantity: 12 });
リストのアイテムは、インデックスとプロパティ名でアクセスできるようになりました。
console.log("Third item: " + cart[2].name);
console.log(cart[2].name + " quantity: " + cart[2].quantity);
このコードを実行した後にコンソールに表示される出力は次のとおりです。
third item: eggs Eggs quantity: 12
データ構造を利用することで、プログラマはコードをより整理することができ、原作者やチーム内の他のプログラマによるメンテナンスが容易になります。また、JavaScriptの関数からの出力の多くは構造型であり、プログラマはこれを適切に処理する必要があります。
演算子
ここまでは、新しく作成した変数に値を代入する方法だけを見てきました。単純なことですが、どんなプログラムでも、変数の値に対して他にもいくつかの操作を行います。JavaScriptには、変数の値を直接操作したり、操作結果を新しい変数に格納したりすることができる、いくつかの種類の 演算子 があります。
ほとんどの演算子は、算術演算を目的としています。例えば、買い物リストのアイテムの数量を増やすには、 +
の加算演算子を使うだけです。
item.quantity = item.quantity + 1;
次のスニペットは、加算前と加算後の item.quantity
の値を表示します。スニペット内のプラス記号の役割を混同しないでください。 console.log
文では、2つの文字列を結合するのにプラス記号を使います。
let item = { name: 'Milk', quantity: 1 };
console.log("Item: " + item.name);
console.log("Quantity: " + item.quantity);
item.quantity = item.quantity + 1;
console.log("New quantity: " + item.quantity);
このコードを実行した後にコンソールに表示される出力は次のとおりです。
Item: Milk Quantity: 1 New quantity: 2
item.quantity = item.quantity + 1
というように、以前に item.quantity
に格納されていた値が加算演算のオペランドとして使用されることに注意してください。演算が完了した後にのみ、 item.quantity
の値は演算結果で更新されます。このように対象変数の現在の値を使った算術演算はよくあることなので、同じ演算を簡略化して書くことができる省略演算子があります。
item.quantity += 1;
その他の基本的な操作にも、同等の省略可能な演算子があります。
-
a = a - b
は、a -= b
と同じです。 -
a = a * b
は、a *= b
と同じです。 -
a = a / b
は、a /= b
と同じです。
足し算と引き算では、第2オペランドが1単位しかない場合、3つ目の形式があります。
-
a = a + 1
は、a++
と同じです。 -
a = a - 1
は、a--
と同じです。
複数の演算子を組み合わせて同じ操作を行い、その結果を新しい変数に格納することができます。例えば、次の文は、商品の価格に送料を加えた合計金額を計算します。
let total = item.quantity * 9.99 + 3.15;
演算の実行順序は、従来の優先順位に従っています。まず乗算と除算の演算が実行され、その後に加算と減算の演算が実行されます。同じ優先順位を持つ演算子は、式の中で左から右の順に実行されます。デフォルトの優先順位を変更するには、 a * (b + c)
のように括弧を使用します。
場合によっては、演算の結果を変数に格納する必要がないこともあります。これは、 if
文の中で式の結果を評価したい場合などです。
if ( item.quantiy % 2 == 0 )
{
console.log("Quantity for the item is even");
}
else
{
console.log("Quantity for the item is odd");
}
%
(モジュロ)演算子は、第1のオペランドを第2のオペランドで割った余りを返します。例題では、 if
文で、 item.quantity
を 2
で割った余りがゼロに等しいかどうか、つまり、 item.quantity
が2の倍数であるかどうかをチェックしています。
演算子 +
のオペランドの一つが文字列の場合、他の演算子は文字列に 強制 され、結果は文字列の連結になります。これまでの例では、このような演算子を使って、文字列と変数を連結して、 console.log
文の引数にしていました。
このような自動変換は、望ましい動作ではない場合があります。例えば、ユーザーがフォームフィールドに入力した値は、文字列として認識されているかもしれませんが、実際には数値である場合があります。このような場合には、まず、 Number()
関数を使って変数を数値に変換する必要があります。
sum = Number(value1) + value2;
さらに、操作を進める前に、ユーザーが有効な値を入力したかどうかを確認することも重要です。JavaScriptでは、値が割り当てられていない変数には、 null
という値が入ります。これにより、プログラマは、変数に割り当てられた値の型にかかわらず、変数に値が割り当てられたかどうかを確認するために、 if ( value1 == null )
のような判定文を使用することができます。
演習
-
配列はいくつかのプログラミング言語に存在するデータ構造ですが、その中には同じ型のアイテムを持つ配列のみを許可するものもあります。JavaScriptの場合、異なる型の項目を持つ配列を定義することは可能ですか?
-
ショッピングリストのオブジェクトの例として、
let item = { name: 'Milk', quantity: 1 }
という例をもとに、ショッピングリスト内のオブジェクトについて、このオブジェクトにアイテムの価格(price)として4.99を含めるように宣言するにはどうしたらよいでしょうか。 -
1行のコードで、変数の値を現在の値の半分に更新する方法は何ですか?
発展演習
-
次のコードでは、コンソール出力にどのような値が表示されますか?
var value = "Global"; { value = "Location"; } console.log(value);
-
掛け算のオペランドの1つ以上が文字列の場合はどうなりますか?
-
let cart = ['Milk', 'Bread', 'Eggs']
と宣言された 'card' 配列から、アイテム 'Eggs' を削除するにはどうればよいでしょう?
まとめ
このレッスンでは、JavaScriptにおける定数と変数の基本的な使い方を説明しました。JavaScriptは 動的型付け言語 なので、プログラマは変数を設定する前にその型を指定する必要はありません。しかし、基本的な操作で正しい結果を得るためには、言語のプリミティブ型を知っておくことが重要です。さらに、配列やオブジェクトなどのデータ構造は、プリミティブ型を組み合わせて、より複雑な複合変数を作ることができます。このレッスンでは、次のような概念と手順を説明しました。
-
定数・変数の理解
-
変数のスコープ
-
var
とlet
による変数の宣言 -
プリミティブ型
-
算術演算子
-
配列とオブジェクト
-
型の強制と変換
演習の回答
-
配列はいくつかのプログラミング言語に存在するデータ構造ですが、その中には同じ型のアイテムを持つ配列のみを許可するものもあります。JavaScriptの場合、異なる型の項目を持つ配列を定義することは可能ですか?
はい、JavaScriptでは、文字列や数値など、異なるプリミティブ型の項目を持つ配列を定義することができます。
-
ショッピングリストのオブジェクトの例として、
let item = { name: 'Milk', quantity: 1 }
という例をもとに、ショッピングリスト内のオブジェクトについて、このオブジェクトにアイテムの価格(price)として4.99を含めるように宣言するにはどうしたらよいでしょうか。let item = { name: 'Milk', quantity: 1, price: 4.99 };
-
1行のコードで、変数の値を現在の値の半分に更新する方法は何ですか?
value = value / 2
のように、変数そのものをオペランドとして使用することもできますし、省略可能な演算子/=
を使用して、value /= 2
とすることもできます。
発展演習の回答
-
次のコードでは、コンソール出力にどのような値が表示されますか?
var value = "Global"; { value = "Location"; } console.log(value);
Location
-
掛け算のオペランドの1つ以上が文字列の場合はどうなりますか?
JavaScriptは、結果に
NaN
(Not a Number)という値を割り当て、操作が無効であることを示します。 -
let cart = ['Milk', 'Bread', 'Eggs']
と宣言された 'card' 配列から、アイテム 'Eggs' を削除するにはどうればよいでしょう?javascriptの配列には、リストの最後の項目を削除する
pop()
メソッドがあります。cart.pop()
です。