マニュアル: JavaScript

投稿日: 更新日:

Can I use

文法

var/let/const

var, let, constの違い

宣言 スコープ 再代入可能
なし グローバル
var 関数
let ブロック
const ブロック

varは不要っぽい

以下の理由から、もうvarは不要かと思われます。

  • IE11を含む主要ブラウザでサポートされている1
    • ただし、IE11のletは一部問題があるらしい(Can I useより)
  • 関数スコープが必要なケースがほとんどない、あっても関数の先頭で宣言すればよい。

this

JavaScriptではthisが呼び出される文脈によって異なっていたためいろいろと問題があった。 解決案は2通り。

  • アロー関数を使う
  • bindを使う
    • foo.bind(this, arg1, arg2)

bind

  • bindの1番目の引数はthisを束縛するもの。nullを指定すると束縛しない
  • bindの2番目以降の引数は関数の引数を束縛する。

アロー関数

Strictモード

Strict モード - JavaScript | MDN

使用方法

他のいかなる文よりも先に"use strict";, または'use strict'; という文をそのまま追加します。

MDNの記事に書かれていますが、 スクリプトの先頭に書くと、webpackなどで連結するときに連結後のスクリプト全体が strictになってしまうので、注意が必要です。 関数ごとに付けるのが安全です

Strictモードによってエラーになるもの

詳細はMDNの記事にありますが、 注意すべきことは以下になります。

  • 8進数が禁止される(間違って使われやすいため)
  • with文が禁止される(最適化のため)
  • evalで宣言した変数は外部に影響しない

Strictモード宣言はただの文字列なので、 未対応ブラウザには影響しません2。 なので、使ったほうが良いです。

比較演算子

以下のように、==は曖昧な比較、===は厳密な比較を行う3

Equality (==) The equality operator converts the operands if they are not of the same type, then applies strict comparison. If both operands are objects, then JavaScript compares internal references which are equal when operands refer to the same object in memory.

  1   ==  1        // true
 '1'  ==  1        // true
  1   == '1'       // true
  0   == false     // true
  0   == null      // false
var object1 = {'value': 'key'}, object2 = {'value': 'key'};
object1 == object2 //false

  0   == undefined // false
null  == undefined // true

Identity / strict equality (===) The identity operator returns true if the operands are strictly equal (see above) with no type conversion.

3 === 3   // true
3 === '3' // false
var object1 = {'value': 'key'}, object2 = {'value': 'key'};
object1 === object2 //false

=====のどちらを使うべきか?

曖昧な比較はバグの元のため、===を使うことが望ましい4

if (foo)if (foo === bar)のどちらを使うべきか?

Javaならif (foo)で決まりなんですが、 JavaScriptではTruthyという「真値っぽい5」判定に使われるので、 なるべくは避けたいところです。

たぶんこんな感じかなぁと。

  • 左辺・右辺ともにboolean: if (foo)
  • 左辺・右辺ともにオブジェクト、undefined、nullのみ: if (foo)
  • それ以外: if (foo === bar)

String

Array

基本操作

Array - JavaScript | MDN

  • 追加削除
    • 最後: push / pop
    • 先頭: unshift/ shift
    • 連結: concat
    • 区切る: join

要素のループ

以下でいいと思います。

for...inは全てのプロパティを反復する(for…of参照)のため、 おそらく意図した挙動ではありません。

最初に見つかった要素を返却

以下でいいと思います。

要素が存在するかどうかをチェック

NodeListなどから変換

以下のArray.fromがいいと思います(IE以外では動きます)。

Date

昨日の日付を取得する

以下のように、setDate()に日付を1引いたものを与える。

var d = new Date();
d.setDate(d.getDate() - 1);

1日の場合も適切に調節してくれるため問題ない[^setDate]。

dayValue がその月の日付の範囲外の値の場合、 それに応じて setDate() が Date オブジェクトを更新します。 例えば、dayValue に 0 を与えた場合、日付は前月の最終日に設定されます。

Iterator

[Symbol.iterator]というメソッドを定義する(この構文よく分からん)。

自分で定義することはないと思いますが、 DDDにおけるAggregatesを実装したときに実装すると便利です。

URLのエンコード

非同期処理

Promise

値の代わりに返すことができるもの。 たぶん「約束手形」と同じですね。

async/await

Promiseだけだとしっくりこないのですが、async/awaitを使うと楽になります。

非同期にする(Promiseを返す)functionにasyncを付けて、 戻り値を同期にしたいときにawaitを付けるだけなので、楽です。

注意点として、forEachとは相性が悪いことです。 for .. ofを使います。

また、(現在は)トップレベルでも使えません。

ただ、これは簡単な回避方法はあります。即時関数を使用するだけです。

(async () => {
  // ここに処理を書く。
})();

Ajax

従来はXMLHttpRequestが使われていましたが、 今後はfetchが使われることになりそうです(polyfillもあります)。

eval

安全なeval

notevilによるevalの実装

たとえば、Moment.jsとsprintfをそのまま使えるようにしたい場合は、 以下のようにします。

const func = safeEval(funcstr, {
  moment: function() {
    return moment();
  },
  sprintf: function(...args) {
    return sprintf(...args);
  }
})

関数の定義の場合は以下のようになります。

safeEval.Function("moment", "sprintf", value['value']).call(this, moment, sprintf);

モジュール

Node.jsでの書き方

module.exportsを使ってこんな感じで書く。

var foo = {
  init: function() {
    ...
  }
}

module.exports = foo;

正確には以下のようになるようです。

  • デフォルトではmodule.exportsexportsは同じ
  • module.exportsにオブジェクトを代入すると、exportsは使えない。

参考: Node.jsのexportsについて - 30歳からのプログラミング

ES2015の書き方はどうか?

モジュールはES2015での書き方もありますが、 自分としてはまだ流動的なので、しばらくは使わない予定です。

  1. Node.jsのModulesに記載がない
  2. Firefoxでデフォルト対応していない(設定が必要)7
  3. 現状特に困ってない

2017年8月現在なので現状と変わっている可能性はありますが、 現段階ではおすすめしないという記事がありました8

ブラウザの互換性

逆引きマニュアル