【JavaScript】ES6やES2017の構文が使えるか判定する方法

JavaScript(ECMAScript)の実行環境によって、[アロー関数](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/arrow_functions)(ES6~)などの新しい構文が使えたり使えなかったりします。
例えば、Internet Explorer 11ではES6以上から使える構文には対応していないので、アロー関数が利用できません。
その構文が使えるか `true` or `false` で返す関数を作ることを考えてみました。

# アロー関数が使えるかどうかを返す関数
通常はあまり使われることがない [`Function` コンストラクタ](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Function)を活用します。
`Function` コンストラクタでアロー関数を含む関数を定義できればアロー関数が使えると考えて良さそうです。

```javascript
function canUseArrowFunction() {
  try {
    Function('x=>1');
    return true;
  } catch (e) {
    return false;
  }
}
```

# ちょっと意地悪してみる
`Function` コンストラクタが `Function = null` などによって使用不能にされた場合においても、関数リテラルを使って`Function` コンストラクタを呼び出すことができました。

```javascript
Function = null;
function canUseArrowFunction() {
  try {
    (function(){}).constructor('x=>1');
    return true;
  } catch (e) {
    return false;
  }
}
```

# 色々な構文で試してみる
* `canUseAsyncArrowFunction`
    * ES2017から使えるようになった[async関数](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/async_function)が使えるか
* `canUseGetSyntax`
    * ES5から使えるようになった[get構文](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/get)が使えるか
* `canUseArrayComprehensions`
    * 最新のブラウザでは使えない、[配列内包](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Array_comprehensions)という古い仕様の構文が使えるか
        * [Google Apps Script](https://developers.google.com/apps-script/) (Rhino)ではまだ使えるらしい[^1]

```javascript
// async/await
function canUseAsyncArrowFunction() {
  try {
    (function(){}).constructor('async x=>1');
    return true;
  } catch (e) {
    return false;
  }
}

// アロー関数(再掲)
function canUseArrowFunction() {
  try {
    Function('x=>1');
    return true;
  } catch (e) {
    return false;
  }
}

// Objectのget構文
function canUseGetSyntax() {
  try {
    (function(){}).constructor('({get x(){}});');
    return true;
  } catch (e) {
    return false;
  }
}

// 配列内包
function canUseArrayComprehensions() {
  try {
    (function(){}).constructor('[x for each(x in [])];');
    return true;
  } catch (e) {
    return false;
  }
}

console.log('canUseAsyncArrowFunction: ' + canUseAsyncArrowFunction());
console.log('canUseArrowFunction: ' + canUseArrowFunction());
console.log('canUseGetSyntax: ' + canUseGetSyntax());
console.log('canUseArrayComprehensions: ' + canUseArrayComprehensions());
```

# 各種実行環境で実験
## Google Chrome 69
<img width="493" alt="chrome.png" src="https://qiita-image-store.s3.amazonaws.com/0/137045/2eb09799-262f-3474-17c9-e2de6b4161fd.png">

古い構文である配列内包(`canUseArrayComprehensions`)は 使えないので `false` になっています

## Internet Explorer 11
![ie11.png](https://qiita-image-store.s3.amazonaws.com/0/137045/79685cad-ce77-4a03-0bb5-024a88d979a3.png)

ES5まで対応なのでget構文(`canUseGetSyntax`)だけが `true` になっています

## Node.js v10
```
canUseAsyncArrowFunction: true
canUseArrowFunction: true
canUseGetSyntax: true
canUseArrayComprehensions: false
```

## Node.js v5
```
canUseAsyncArrowFunction: false
canUseArrowFunction: true
canUseGetSyntax: true
canUseArrayComprehensions: false
```

async/awaitが使えないようです(`canUseAsyncArrowFunction`)

## Google Apps Script [^1]
### Rhino JavaScript interpreter
<img width="905" alt="gas.png" src="https://qiita-image-store.s3.amazonaws.com/0/137045/517df88b-7ffc-1c99-f0e1-d919eb7c01a4.png">
配列内包(`canUseArrayComprehensions`)が `true` になっています 
get構文(`canUseGetSyntax`)についても `true` になっています

### V8 Runtime
<img width="905" alt="gas2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137045/8121f812-795b-ff73-a3e1-2caba6bd7b43.png">
Rhino だと配列内包(`canUseArrayComprehensions`)が `true` でしたが `false` になりました。
GAS のランタイム判定に使えるかもしれません。

## Adobe Extendscript Toolkit CS6
![extendscript.png](https://qiita-image-store.s3.amazonaws.com/0/137045/37c11ed7-8544-b1aa-a794-8b7a7baa24db.png)
ExtendscriptはES3までしか使えないらしく、すべて `false` でした

# まとめ
Google Apps Scriptで今では非標準となった構文が使えるのが意外でした。この記事を書きながら、JavaScriptの複雑な歴史を感じてました。
(Extendscript や Google Apps Script で最新の ECMAScript の構文をトランスパイルなしで使える日は来るのでしょうか...?)

# 参考サイト
* [nmm実験室 - ES6 が使えるかの JavaScript での確認方法](http://var.blog.jp/archives/60184433.html)

[^1]: (2020/02/06追記) 記事投稿時は Google Apps Script のランタイムとして Rhino JavaScript interpreter のみ提供されていましたが、現在では V8 も提供されるようになりました https://developers.google.com/apps-script/guides/v8-runtime