JavaScriptやその仕様であるECMAScriptは年々進化しています。ネットで検索すると5年くらい前のコードも見つかるので、ついそのまま使ってしまいがちですが、書き方が古いままになっていることもよくあります。

古い書き方の場合、思わぬ不具合につながったり、メンテナンスのしづらいスパゲティコードになってしまいがちです。ハイブリッドアプリでは対象となるWebブラウザが最新のChromeやSafariをベースにしていますので、新しいJavaScript構文も積極的に取り入れられます。この記事ではそうしたモダンな構文の書き方とそのメリットを解説します。

let/constを使った変数宣言

かつてのJavaScriptでは変数宣言としてvarを使っていました。

var hello = 'Hello world';

このvarは今も使えますが、現在は推奨されていません。代わりに let / const を使います。

let

let は変更できる変数を定義します。なおかつ、JavaScriptのブロック(波括弧)内でのみ有効(スコープといいます)な変数になります。ブロック外には影響しないので、自分が期待している場所以外では利用できない形に制御できます。

if (true) {
  let monaca = 'Monaca'
  console.log(monaca)
  // => Monaca
} else {
  console.log(monaca)
  // => Uncaught ReferenceError: monaca is not defined
}
console.log(monaca)
// => Uncaught ReferenceError: monaca is not defined

関数の中でletを使うことで、その関数の中でしか使えない変数にできます。

function Hello() {
  let monaca = 'Monaca'
  console.log(monaca)
  // => Monaca
}
Hello()
console.log(monaca)
// => Uncaught ReferenceError: monaca is not defined

そして、letで定義された変数は上書きできます。

function Hello() {
  let monaca = 'Monaca'
  console.log(monaca)
  // => Monaca
  monaca = 'Changed'
  console.log(monaca)
  // => Changed
}
Hello()
console.log(monaca)
// => Uncaught ReferenceError: monaca is not defined

基本的に、従来varで定義していたものはletに置き換えできるでしょう。

const

さらにJavaScriptでは変数はletではなくconstでの定義を推奨しています。constはletと異なり上書きできません。

const monaca = 'Monaca'
monaca = 'Changed'
// => Uncaught TypeError: Assignment to constant variable.

上書きできないということは、定義した変数の内容が変わらないのが保証されるので、定数などにも向いています。ただし、配列は追加や削除できたり、オブジェクトはキーの追加、変更ができるので注意してください。

const ary = []
// 追加できます
ary.push(1)
// 変更できます
ary.splice(0, 1, 2)
ary[0] = 3
// 丸ごと変更はエラーです
ary = ['1']
// => Uncaught TypeError: Assignment to constant variable.

オブジェクトも同様です。

const obj = {a: 'b'}
// 追加できます
obj.c = 'd'
// 変更できます
obj.a = 'c'
// 丸ごと変更はエラーです
obj = {e: 'f'}
// => Uncaught TypeError: Assignment to constant variable.

関数でも利用できます

JavaScriptの関数は繰り返し定義可能で、上書きできてしまいます。

function Hello() {
  return 'Monaca'
}
console.log(Hello())
// => Monaca
function Hello() {
  return 'Onsen UI'
}
console.log(Hello())
// => Onsen UI

関数名が重複していたために思わぬ動作不具合に繋がるのを防止する目的としてconstを使うこともできます。

const Hello = function() {
  return 'Monaca'
}
console.log(Hello())
// => Monaca

function Hello() {
  return 'Onsen UI'
}
// => Uncaught SyntaxError: Identifier 'Hello' has already been declared

このようにlet/constを使うことで、規模が大きなJavaScriptソースであっても安全に、メンテナンスしやすいコードを維持できます。

class構文

JavaScriptには元々クラスという概念がなく、functionを使った擬似的クラスでコーディングされていました。しかし最近ではクラスが使えるようになっています。ECMAScript 2019では # を使ってプライベート変数(クラス内だけで参照できる変数)も定義できるようになっています。

class App {
  #_name
  constructor (name) {
    this.#_name = name
  }
  say () {
    return `My name is ${this.#_name}`
  }
  static classMethod () {
    return 'This is class method'
  }
}

使い方は class でクラスを定義し、new (クラス名) で利用可能になります。

const app = new App('Monaca')
console.log(app.say())
// => My name is Monaca
console.log(App.classMethod())
// => This is class method

継承も可能です。

class App2 extends App {
  newMethod() {
    return `${this.say()}, from new Method.`
  }
}

継承したメソッドはもちろん、新しいクラスからのみ使えます。

const app2 = new App2('Onsen UI')
console.log(app2.newMethod())
// => My name is Onsen UI, from new Method.

class構文を使うことで、アプリ内の機能をまとめることができたり、別な画面でも利用する同じような機能を再利用しやすくなります。ぜひ積極的に使ってみてください。

アロー関数(Arrow Functions)

JavaScriptでは関数を定義する際には function を使うのが一般的です。

function Hello() {
  return 'Monaca'
}

それに対してアロー関数は () => という形を取ります。

const Hello = () => {
  return 'Monaca'
}

細かな違いは色々ありますが、一番大きな違いは通常の関数とアロー関数はthisの扱いがまったく異なります。functionで書いた場合には次のようになります。DOMをクリックしたタイミングでは対象になるDOM(h3)が取れますが、fetchした後はWindowオブジェクトに変わっています。このthisの取り扱いが異なるところがJavaScriptの難しさに感じるでしょう。

const dom = document.querySelector('h3')
dom.addEventListener('click', function(e) {
  console.log(this)
  // => <h3>...</h3>
  fetch('https://petstore.swagger.io/v2/swagger.json')
    .then(function(res) {
      console.log(this)
      // => Window
    })
})

これがアロー関数を使った場合、DOMではなくWindowオブジェクトが返ってくるようになります。

const dom = document.querySelector('h3')
dom.addEventListener('click', e => {
  console.log(this)
  // => Window
  fetch('https://petstore.swagger.io/v2/swagger.json')
    .then(res => {
      console.log(this)
      // => Window
    })
})

他にも、アロー関数の場合は引数が一つの場合は括弧を省略して書けます。

const Hello = (name) => {
  return `My name is ${name}`
}

これは次のように書けます。

const Hello = name => {
  return `My name is ${name}`
}

さらに一行でデータを返却する場合には波括弧とreturnを省略できます。つまり下記のように記述できます。

const Hello = name => `My name is ${name}`

分割代入(Destructing Assignment)

関数などの返却値としてオブジェクトを返すことがあると思います。例えば複数の値をまとめて返したい時です。

function Hello() {
  return {a: 'b', c: 'd'}
}

この時、返り値を波括弧で受け取ることができます。

const {a, c} = Hello()
console.log(a)
// => b
console.log(c)
// => d

存在しないキー名を指定してもエラーにはなりませんが、変数の内容は存在しません。下記の例の場合 const で指定していますので、変数dには別な値を設定できません。

const {a, d} = Hello()
console.log(a)
// => b
console.log(d)
// => undefined

分割代入はオブジェクトだけでなく、配列でもできます。

function Hello() {
  return [1, 2, 3]
}

この場合は変数名は決まったものではなく、前から順番に代入されます。

const [a, b, c, d] = Hello()
console.log(a)
// => 1
console.log(b)
// => 2
console.log(c)
// => 3
console.log(d)
// => undefined

あらかじめキー名が分かっているオブジェクトを扱う場合、返却される配列の要素数が分かっている場合などに便利です。

配列展開(Array Spread)

例えばある数の集合の中で最大の数を見つけるのに使うのがMath.max関数です。この関数は次のように使います。

Math.max(1, 3, 10, 4, 5)
// => 10

数を並べないといけないのですが、この数がプログラミングによって可変で変わる場合はどうしたらいいでしょうか。昔は次のように書いていました。

const ary = [1, 3, 10, 4, 5]
Math.max.apply(null, ary)
// => 10

これを簡単にしてくれるのが配列展開です。配列の内容を引数に展開してくれる仕組みです。 ... を使います。

Math.max(...ary)
// => 10

同じような例として配列の連結にも使えます。

let ary = [1, 2]
ary = [...ary, ...[3, 4]]
console.log(ary)
// => [1, 2, 3, 4]

上記の例ではaryを再代入しているのでletを使っていますが、次のようにすればconstが使えます。

const ary = [1, 2]
ary.push(...[3, 4])
console.log(ary)
// => [1, 2, 3, 4]

これは配列だけでなくオブジェクトでも利用できます。オブジェクトをコピーするのに便利です。

const obj = {a: 'b', c: 'd'}
const obj2 = {e: 'f', ...obj}
console.log(obj2)
// => {e: "f", a: "b", c: "d"}

テンプレート文字列(Template Strings)

テンプレート文字列はこれまでのサンプルコードでも何回か登場しています。これまで、文字の中に変数の内容を入れる場合には次のようにしなければなりませんでした。

const name = 'Monaca'
const myName = 'Hello, my name is ' + name
console.log(myName)
// => Hello, my name is Monaca

この方法の場合、文字列の中に"(ダブルクォート)や'(シングルクォート)を入れたい時に不便だったり、+を使って文字列を連結するのでコードが見づらくなります。例えばHTMLを文字列で作る際に、次のようなコードを書いた経験は誰しもあるのではないでしょうか。

const title = 'Monaca'
const url = 'https://ja.monaca.io/'
const html = '<a href="'+ url +'">' + title + '</a>'
console.log(html)
// => <a href="https://ja.monaca.io/">Monaca</a>

シングルクォートとダブルクォートの使い分けも面倒ですし、文字列が分かれてしまうので閉じタグをミスしてしまったりします。これを防げるのがテンプレート文字列になります。上記のHTMLの例の場合、次のように書けます。

const html = `<a href="${url}">${title}</a>`
console.log(html)
// => <a href="https://ja.monaca.io/">Monaca</a>

利用するのは(バッククォート)になります。その中では${} を使ってJavaScriptが書けます。変数をそのまま展開するのはもちろん、計算式も入れられます。

const i = 1
const result = `答えは${i * 2}です`
console.log(result)
// => 答えは2です

テンプレート文字列の場合、改行も利用できます。この点も便利です。

const name = 'Monaca'
const text = `テキストです。
${name}ではモダンなJavaScriptを使って
アプリ開発ができます。
`

まとめ

このようにJavaScriptはモダンな書き方が多数用意されています。昔ながらの書き方も使えますが、コード量を短くしたり、全体の見通しをよくするためにモダンな書き方を積極的に取り入れていくべきです。

他にもJavaScriptには多くの構文がありますので、ぜひ学んでみてください。

JavaScript reference - JavaScript | MDN