こんにちは。フロントエンドエンジニアのほりでーです。
今回はES6の新機能であるテンプレートリテラルとimport/exportステートメントについてご紹介いたします!
目次
テンプレートリテラルとは
これまでJavaScriptで文字列をあつかう際には、リテラルとして「'
(シングルクォート)」か「"
(ダブルクォート)」を使っていました。ES6では、あらたに「
`
(バッククォート)」によっても文字列をあつかえるように。この「`
」で表現された文字列リテラルを、テンプレートリテラル(または、テンプレートストリングス)と呼びます。
テンプレートリテラルを使うと、通常の文字列リテラルとは異なり、下記のような恩恵を受けられます。
- 途中でもエスケープなしで改行文字を含められる
${…}
記号を使って文字列の途中にJavaScriptを混ぜられる- タグ付テンプレートリテラル、という使い方ができる
他の言語に登場する、ヒアドキュメントとよく似た概念と言えるでしょう。
では早速、それぞれの詳細について見ていきましょう。
途中にエスケープなしで改行文字を含められる
これまでHTMLコードのようなまとまった文字列をあつかう際には、改行なしで無理矢理あつかうか、演算記号を駆使してそれっぽく書くしかありませんでした。
// 文字列リテラルによる改行の表現
let myString = '改行は\nで表現';
let myString2 = '無理やり\n' +
'改行を表現';
// テンプレートリテラルによる改行の表現
let templateString = `改行は
そのまま
表現できます。`;
しかし、テンプレートリテラルであれば、改行をそのまま使ってもOK! コードの見通しを良くする上で、ぜひ使いたい機能ですね。
${…}
記号を使って文字列の途中にJavaScriptを混ぜられる
テンプレートリテラルでは文字列の途中にJavaScriptコードを手軽に混ぜることができます。たとえば、下記のような関数があったとします。
function createHtmlView(content, class) {
return '<p class="' + class + '">' + content + '</p>';
}
よくある書き方ですが、「'
」と「"
」が連続するので、間違えやすく、メンテナンスし辛いコードです。
これをテンプレートリテラルによって置き換えると、次のようになります。
function createHtmlView(content, class) {
return `<p class="${class}">${content}</p>`;
}
${…}
で囲った部分が、直接変数で置き換えられます。明らかにこちらの方がシンプルで読みやすい書き方になっているのがわかります。
タグ付テンプレートリテラル、という使い方ができる
テンプレートリテラルは、関数の引数として特殊な使い方もできます。
console.log('丸括弧の内側に引数を入力');
通常、JavaScriptでは関数を呼び出すときに必ず上記のように丸括弧()を使用します。
しかし、テンプレートリテラルを使うと、この丸括弧を省略して関数を呼ぶことができます。
console.log`丸括弧がなくても関数を呼べちゃいます`;
これがタグ付きテンプレートリテラルです。さらに、タグ付きテンプレートリテラルで呼び出された関数には、次のようなルールで引数が渡されます。
- 第1引数:テンプレートリテラルから
${}
を除いた部分の文字列が、${}区切りの配列として渡される。この配列にはraw
という名前のプロパティもあり、このプロパティ内には文字のエスケープ処理がされていない名前の文字列が格納されている - 第2引数以降:テンプレートリテラル内の
${}
内の値が順番に渡される
もし呼び出された関数に返り値がある場合は、テンプレートリテラルの最終的な値は、その返り値に等しくなります。このあたりの挙動は、言葉で読むよりも実際のコードを見た方が理解しやすいかと思いますので、上記のサンプルをご覧ください。
import/exportステートメントとは
JavaScriptの大きな弱点の1つが、複数ファイルに分けて開発する手段が用意されていなかったことです。ES6では、ついにそのための機能が規定されました。それがimport
ステートメントとexport
ステートメントです。
importは、他のファイルのために、自ファイル内の関数・変数・定数・クラスを公開するステートメントで、exportは、他のファイルで公開されている関数・変数・定数・クラスを自ファイル内で使えるようにするステートメントです。
defaultを使った1番簡単な使い方
それでは、1番シンプルで簡単な使い方を説明します。
例としてimport
する側のファイルmain.js
と、importされる側のファイルawesomeFunction.js
があり、両者は同じ階層に所属している状況を想定します。
// awesomeFunction.js
function awesome(something) {
console.log(`Do ${something} awesome job!`);
}
awesomeFunction.js
には、上記のようなある関数が定義されています。
このままでは当然、main.js
内からawesomeFunction.js
内の機能を使うことはできません。そこで、まずはmain.js
から呼びたい機能にexport
ステートメントとdefault
キーワードを付与します。
// awesomeFunction.js
export default function awesome(something) {
console.log(`Do ${something} awesome job!`);
}
export
ステートメントは、関数以外に変数(var,let)・定数(const)・クラス(class)にも付けることができます。export
ステートメントが付くことで、その関数・変数・定数・クラスを、他のファイルからimport
できる準備が整ったということになります。逆にexport
が付かないものを呼ぶことはできません。
export defaultの意味
export
に続くdefault
キーワードは、switch
文でのdefault:
とは全く意味が異なるので注意してください。
export
のあとにdefault
が付くときは、「このファイルのデフォルトのexport
はこれだよ〜」の意味になり、通常のexport
よりも簡単にimport
できて便利です。ただし、default
キーワードは1つのファイルにつき1つのexport
にだけ有効です。
import
次に、main.js
からawesome関数を呼び出してみましょう。
// main.js
import awesome from './awesomeFunction.js';
awesome('Great');
import
ステートメントは、import … from ファイルパス
の型で使用します。from
より手前の部分が、main.js
内でのawesome関数の識別子になります。
// main.js
import myFunction from './awesomeFunction.js';
myFunction('Great');
つまり、このように書いても機能としては変わりません。
from
より後ろのファイルパスの部分では、実際には拡張子(.js)を省略して書くことができます。慣れてきたら不要でしょう。ファイルパスはルート(/)から始まる絶対パスとして書くか、import
が書かれているファイルを基準とした相対パスとして解決されます。
複数の要素をimport/exportしたいとき
前述の例では、import
/export
するのは1つの要素のみで、複数の要素をあつかうことはできませんでした。しかし、複数の要素をあつかう方法も用意されています。次のようなexportSample.js
があったとしましょう。
// exportSample.js
export let item1 = 'This is item1.';
export const item2 = 'This is item2.';
export function item3(){ return 'This is item3.'; }
export class Item4 {
constructor() { console.log('This is item4.') }
}
これらをすべてimport
するには、main.js
に次のように記載します。
方法1
// main.js
// 方法1
import {item1, item2, item3, Item4} from './exportSample';
// 方法1の呼び出し方法
console.log(item1 + item2);
console.log(item3());
new Item4();
方法1では、from
の前にexportSamples.js
内で宣言されている名前と同じ名称をオブジェクトの中に記述し、その名前を使って呼び出しをしています。
// main.js
// asでエイリアスを設定できる
import {item1 as i1, item2 as i2, item3 as i3, Item4 as I4 } from './exportSample';
console.log(i1 + i2);
console.log(i3());
new I4();
また、このようにas
を使って別の名前(エイリアス)を設定することもできます。
方法2
// main.js
// 方法2
import * as samples from './exportSample';
// 方法2での呼び出し方法
console.log(samples.item1 + samples.item2);
console.log(samples.item3());
new samples.Item4();
方法2では、samples
というオブジェクトの配下にexport
された要素がぶら下がった型になっています。
defaultとの組み合わせ
最初に説明したdefault
と、後述した{name1, name2 as alias}
、* as alias
の書き方は併記することが可能です。
// SampleClass.js
// 定数をexport
export const MESSAGE = 'this is the message.';
// 関数をexport
export function utilityFunc(str) { return str + str; }
// クラスをdefaultでexport
export default class MyClass {
constructor() {
this.msg = utilityFunc(MESSAGE);
}
}
このような内容のJSファイルSampleClass.js
があるとします。このSampleClass.js
は……
// main.js
import MyClass, {MESSAGE as mcMsg, utilityFunc as mcUtilFunc} from 'SampleClass';
// importしたものを実際に使用
new MyClass();
console.log(mcMsg);
mcUtilFunc('my message');
このように呼び出したり……
// main.js
import MyClass, * as mc from 'SampleClass';
// importしたものを実際に使用
new MyClass();
console.log(mc.MESSAGE);
mc.utilityFunc('my message');
このように呼び出したりすることもできます。
import/exportステートメントのまとめ
このように、import/exportでは
export default …
/import … from ファイルパス
で1つの要素だけを読み込むexport …
/import {…} from ファイルパス
で任意の複数の要素を読み込むexport …
/import {… as … } from ファイルパス
で、任意の複数の要素をエイリアス名で読み込むexport …
/import * as … from ファイルパス
で、全ての要素を指定したオブジェクトのプロパティにぶら下げて読み込む- 1と2〜4を組み合わせて使用する
といった使い方が用意されています。特にdefault
はexportされている名前を知らなくてもimportできるので、1番便利です。
あまりたくさんの要素をexport
すると名前を追いかけるのが徐々に面倒になってきそうなので、できるだけimport
/export
する要素を増やしすぎない方が、使いやすいのではないでしょうか。
さいごに
テンプレートリテラルやimport
/export
機能は、どちらもJavaScriptコードの見通しを良くする上でとても便利な機能です。前者は複雑でメンテナンスしづらかった文字列のあつかいを改善することができ、後者はファイルを機能単位で分割して1つ1つのファイルのコード量を減らすことができます。
筆者の場合は、import
/export
機能を使ってファイルを共通関数やクラスごとに分割して管理しています。よりオブジェクト指向的なプログラミングがしやすくなったり、コード資産の再利用性アップに直結したりするのではないでしょうか。これからますます面白くなっていくJavaScriptワールドを楽しむためにも、ぜひES6の機能を使ってみてください!
LIGはWebサイト制作を支援しています。ご興味のある方は事業ぺージをぜひご覧ください。