使いこなそう!テンプレートリテラルとimport/exportステートメント

ほりでー


使いこなそう!テンプレートリテラルとimport/exportステートメント

こんにちは。フロントエンドエンジニアのほりでーです。
今回は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では

  1. export default …/import … from ファイルパスで1つの要素だけを読み込む
  2. export …/import {…} from ファイルパスで任意の複数の要素を読み込む
  3. export …/import {… as … } from ファイルパスで、任意の複数の要素をエイリアス名で読み込む
  4. export …/import * as … from ファイルパスで、全ての要素を指定したオブジェクトのプロパティにぶら下げて読み込む
  5. 1と2〜4を組み合わせて使用する

といった使い方が用意されています。特にdefaultexportされている名前を知らなくてもimportできるので、1番便利です。

あまりたくさんの要素をexportすると名前を追いかけるのが徐々に面倒になってきそうなので、できるだけimport/exportする要素を増やしすぎない方が、使いやすいのではないでしょうか。

さいごに

テンプレートリテラルやimport/export機能は、どちらもJavaScriptコードの見通しを良くする上でとても便利な機能です。前者は複雑でメンテナンスしづらかった文字列のあつかいを改善することができ、後者はファイルを機能単位で分割して1つ1つのファイルのコード量を減らすことができます。

筆者の場合は、import/export機能を使ってファイルを共通関数やクラスごとに分割して管理しています。よりオブジェクト指向的なプログラミングがしやすくなったり、コード資産の再利用性アップに直結したりするのではないでしょうか。これからますます面白くなっていくJavaScriptワールドを楽しむためにも、ぜひES6の機能を使ってみてください!

ほりでー
この記事を書いた人
ほりでー

フロントエンドエンジニア

関連記事