##letキーワードを使用したブロックスコープ変数の宣言
####letキーワードについて
ES5において、varキーワードを使用して変数宣言をする際、もし関数の外で変数を宣言すればグローバル変数になり、関数の中で宣言すればローカル変数になります。
ES6では、letキーワードを使用した新しい変数宣言の方法が提供されています。
letキーワードは、ブロックスコープ変数になることを除けばvarキーワードに似ています。
letを使用した変数宣言の構文を以下に記載します。
let variable_name;
javascriptにおいて、ブロックは中括弧で示されます。
例えば、if else、do while、for、などの構文で使用されます。
以下の例文を使用して説明します。
let x = 10;
if (x == 10) {
let x = 20;
console.log(x); // 20: 内部ブロックの変数xを参照
}
console.log(x); // 10: 最初に宣言された変数xを参照
- まず最初に、変数xを宣言しxに10を代入しています
- 次にifブロックの中で変数xを宣言し、xに20を代入しています
- 最後にifブロックの外で、変数xの値を出力しています
letキーワードを使用して宣言された変数は、ブロックスコープ変数であるので、ifブロック内の変数xは新しい変数であり、スクリプトの最初に宣言された変数xはこの中では参照されません。
それゆえ、ifブロック内のコンソールには20が出力されます。
Javascriptエンジンがifブロックの実行を完了したとき、ifブロック内にあるxの値はスコープ範囲外となります。それゆえ、ifブロックの次に表示されるxの値は10となります。
####letキーワードとグローバルオブジェクト
varキーワードを使用してグローバル変数を宣言すれば、その変数はグローバルオブジェクトのプロパティリストに追加されます。例えば、Webブラウザにおけるグローバルオブジェクトとはwindowのことです。
次の例をご覧ください。
var a = 10;
console.log(window.a); // 10
しかし、letキーワードを使用して宣言された変数は、プロパティとしてグローバルオブジェクトに割り当てられません。
let b = 20;
console.log(window.b); // undefined
####forループ構文におけるlet及びコールバック関数
以下の例をご覧ください。
for (var i = 0; i < 5; i++) {
setTimeout(function () {
console.log(i);
}, 1000);
}
このスクリプトの実行結果としては、0から4の価が順に表示されると予想されますが実際は、数字の5が5回表示されます。
その理由としては、iの値が5になったあとに5回繰り返されるからです。そして、setTimeOut()に渡されたコールバック関数の5つのインスタンスは、最終値5がセットされた変数iを参照しています。
ES5において、これを解決するにはコールバック関数のそれぞれのインスタンスが新しい変数を参照する必要があります。そして、以下のように新しいスコープを作成するために新しい関数を作成する必要があります。
for (var i = 0; i < 5; i++) {
(function (j) {
setTimeout(function () {
console.log(j);
}, 1000);
})(i);
}
ES6においては、letキーワードを使用すればループにおいて新しい変数を参照できます。
上記の例では、varをletに置き換えるだけで実現できます。
for (let i = 0; i < 5; i++) {
setTimeout(function () {
console.log(i);
}, 1000);
}
また、ES6スタイルとしてアロー関数を用いると以下のように書くことができます。
for (let i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 1000);
}
####変数の再宣言
varは問題なく変数の再宣言を行うことができます。
var counter = 0;
var counter;
console.log(counter); // 0
しかし、letキーワードを使用して再宣言するとエラーになります。
let counter = 0;
let counter;
console.log(counter);
Uncaught SyntaxError: Identifier 'counter' has already been declared
####まとめ
letキーワードを使用した変数の特徴としては、以下となります。
- ブロックスコープ変数
- いかなる値にも初期化されない
- グローバルオブジェクトには割り当てられない
- 変数の再宣言をするとエラーになる
ES6においては、変数の宣言をする際はvarではなくletを使用することが推奨されます。
##ES6における定数の宣言
このセクションでは、constキーワードを使用した定数の宣言方法について記載します。
####constキーワードについて
ES6ではconstキーワードを使用した新しい定数の宣言方法が追加されました。
constキーワードで宣言すると、その値は読み取り専用として格納されます。
const CONST_NAME = value;
constキーワードは、letキーワードのような働きをしますが、再定義できないブロックスコープ変数として定義されます。
letキーワードで宣言された変数は、可変変数です。すなわち、以下の例のようにいつでも変更することができます。
let a = 10;
a = 20;
a = a + 5;
console.log(a); //25
constキーワードで宣言された変数は、不変変数です。すなわち、一度定義すれば再定義できません。
以下の例のように、再定義しようとするとエラーになります。
const a = 2;
a = 3; //TypeError
また、constキーワードを使用して変数を宣言すると即座に値を初期化する必要があります。
初期化せず宣言すると以下の例のように構文エラーになります。
const a; //SyntaxError
letと同じくconstもブロックスコープ変数として宣言されます。
####const変数とオブジェクト
const変数は、読み取り専用の変数ですが、以下の例のように、const変数が参照しているオブジェクトのプロパティ値は変更可能となります。
const person = {age:20};
person.age = 30;
console.log(person.age); //30
たとえpersonがconstで宣言された変数であったとしても、そのプロパティ値を変更することができます。
しかし、以下のような変更はエラーとなります。
person.age = 40; //TypeError
もし、personオブジェクトを変更不能な変数として宣言したいのであればobject.freeze()メソッドを使用することにより、それが可能となります。
const person = object.freeze({age:30});
person.age = 40; //TypeError
ここでは、companyオブジェクトのプロパティは変更不可ですが、プロパティに参照されているオブジェクトは変更不可ではありません。
以下の例ですとcompanyオブジェクトは変更不可ですが、company.addressオブジェクトは変更かのうとなります。
const company = object.freeze({
name: 'ABC corp',
address: {
street:'North 1st Street',
city: 'New York',
zipcode: 95134
}
});
company.address.country = 'USA'; // OK
####constを使用した配列の宣言
以下の例では、constを使用してcolor配列を宣言しています。
要素greenを追加することができますが、color配列を再定義することはできません。
const colors = ['red'];
colors.push('green');
console.log(colors); // ['red','green']
colors.pop();
colors.pop();
console.log(colors); // []
colors = ['yellow']; // TypeError
##Javascriptにおけるテンプレートリテラル
このセクションでは、Javascriptにおけるテンプレートリテラルの使い方についてお伝えします。
ES6以前では、文字列を囲むのにシングルクウォート(')あるいはダブルクウォート(")を使用していました。
そしてそれらは、機能的に非常に限定的でした。
これらの問題を解決するため、ES6ではより簡単により安全に文字列を表すテンプレートリテラルが提供されています。
ES6では以下のようにバッククウォート(`)を使用して文字列を囲むことにより、テンプレートリテラルを作成することが可能です。
let simple = `This is a templete literal`;
この方法で行うことにより、以下のことが可能になります。
- 文字列を複数行に分ける
- 変数の値を文字列の一部に置き換える
####テンプレートリテラルの基本的な構文
シングルクウォートやダブルクウォートに代わる方法として、テンプレートリテラルは以下のように、バッククウォートを使用します。
let str = `Templete literal in ES6`;
console.log(str); // Templete literal in ES6
console.log(str.length); // 23
console.log(typeof str); // string
バッククウォートを使用することにより、エスケープすることなくテンプレートリテラル内にシングルクウォートやダブルクウォートを自由に使用することができます。
let str = `Here's is a templete literal`;
もし以下の例のように、文字列の中にバッククウォートを含んでいればバックスラッシュ()を使用してエスケープする必要があります。
let str = `Templete literal use backticks \` instead of quotes`;
####複数行の表現方法
ES6より以前では、文字列の改行をするために改行文字(\n)を使用していました。
var msg = 'Multiline \n\
string';
console.log(var);
// Multiline
// string
この方法では、文字列の続きを表すため改行文字(\n)の後にバックスラッシュ()を置く必要があります。
しかしながら、このやり方はJavascriptエンジンでは一般的ではありません。
それゆえ複数行を表現する方法として、以下の様に配列を使用して文字列を連結することが非常に一般的でした。
var msg = ['This text',
'can',
'span multiple lines'].join('\n');
テンプレートリテラルでは、複数行を表現するのが非常に簡単になりました。
let msg = `This text
can
span multiple lines`;
##文字列内の変数の置換
テンプレートリテラルのもう一つの特徴として、文字列の中に変数や式を埋め込むことが可能です。
変数や式を置換するために以下の様に記載します。
${valuable_name};
let firstname = 'John';
let lastname = 'Doe';
let greeting = `Hi ${firstname},${lastname}`;
console.log(greeting); // Hi John Doe
上記の例では、greeting文字列の中に変数firstname及びlastnameを埋め込むために、${firstname}及び${lastname}を使用することにより置換しています。
以下の例では、式を埋めこむことにより文字列を置換しています。
let price = 8.99;
let tax = 0.1;
var netPrice = `Net Price:$${(price * (1 + tax)).tofixed(2)}`;
console.log(netPrice); // Net Price:$9.89