JavaScript Tip集(随時更新)

# この記事の内容
個人的に感じた。JavaScriptの罠、有用な点など、随時更新予定

# 一般編
チェックはnodeでやってるのでもしかしたらnodeのせいかも、JavaScriptはブラウザ依存性は強いので細かくはブラウザによりけりになります。

## var, let, const
### var
varのは関数スコープでしか切られない。

```js
c=0; // NG。'use strict'を使っていなければグローバル変数になる。
a=10; // OK
{
  var a=0;
  d=0; // NG、グローバル変数になる。
  (function(){
    var d=0;
  }());
}
```
要はvarは使うな。

### const
constは再代入不可、操作はOK

```js
const obj={};
obj.name='hoge' // OK;

const str='';
str+='hoge' // NG

const i=0;
i++; // NG

for( const a of [ 1, 2, 3, 4, 5 ] ){ // OK
   console.log(a); 
}

const arr=[ 1, 2, 3, 4, 5 ]; 
for( const i=0; i<arr.length; i++ ){ ~ } // NG i++があるから 
```
C++だと変化する操作もNGなので勘違いしていた。`+=``++`あたりは再代入と解釈されるのでconstでは使えない。(babelではトランスパイル時エラーになる)。

### let
再代入可能、どうしても代入したい時に

## 7つのプリミティブ型
`boolean``number``string``symbol``object``null``undefined`
### boolean/string
真偽値/文字列

### number
int(整数)、double(浮動点小数)は存在しない。numberは`++`で`1.0`足される。

```js:
let num=0.5;
num++; // num=1.5
```
内部的にはすべて[IEEE 754の64bit浮動点小数](https://ja.wikipedia.org/wiki/IEEE_754#64.E3.83.93.E3.83.83.E3.83.88.E5.80.8D.E7.B2.BE.E5.BA.A6)として扱われる。
int(整数)、double(浮動点小数)は存在しないがどちらとして扱いたいかが重要なの時は形名を書くときはint/doubleで書くことを薦める。

### symbol
まだちょっと理解していないので勉強中。

### object
JavaScriptの**最大の特徴**。`function`や`Array`もオブジェクトの一種です。

#### プロトタイプベース
`prototype`に色んな物をはやしていこうとする方法。プリミティブも基本的にはラッパーオブジェクトから`prototype`にアクセスできるのでJavaScriptではほぼすべてのモノが`prototype`を持っていると言ってもいい。ただし、一部例外があるので注意。
個人的にはprototypeに触るのは禁止、そういったことをしたいときはclass構文で対応することを薦める。

#### ラッパーオブジェクト
boolean,string,number,symbolに対応するオブジェクトが存在しBoolean、String、Number、Symbol、プリミティブ型のメソッドが呼ばれると一時的にこいつらに変換されそのメソッドが呼ばれる。

#### toString
JavaScriptは**ほぼ**すべて`toString`メソッドを持っている。プリミティブ型も自動的にラッパーオブジェクトに変換されその`toString`が呼ばれる。`+`演算子は文字列の結合の意味もあるので`+`を使うと文字列になる場合がある。

### nullとundefined
nullは代入不可、undefinedは代入可能。undefinedは`void 0`で表現可能。~~[しかし`null`は予約語ではないらしい。???](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Reserved_Words)~~[`null`はリテラル](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Lexical_grammar)同じくリテラルの`true`と`false`も代入出来なかった。

```js
let null=1; // エラー
let undefined=0; // OK
const undefined=null; // OK
undefined=null; // 'use strict' してないならOK

console.log(null, undefined);  // null undefined
console.log(Object.prototype.toString.call(null), Object.prototype.toString.call(undefined)); // [object Null] [object Undefined]
console.log(Number(null), Number(undefined)); // 0 NaN
console.log(String(null), String(undefined)); // null undefined
console.log(Array(null), Array(undefined)); // [ null ] [ undefined ]
console.log(Object(null), Object(undefined)); // {} {}
// console.log(null.toString(), undefined.toString());　// 例外 TypedError
```
nullもundefinedも値を持つので配列には入れられる。[object Null]や[object Undefined]は擬似クラスで実体にアクセスすることは出来ない。メソッドも持てないのでtoStringも呼べない。

## 巻き上げ
#### Undefined is not defined
何当たり前のこと言ってんだ:hushed:と思うと死ぬ。

```js:strange.js
{
  console.log(undefined);
  const undefined=0;
}
```
3行目をコメントアウトすると普通に動きます、変数の巻き上げとかとの絡みです。
2行目でグローバル変数の`undefined`をプログラマーは期待しているが3行目でconstで定義をしているので
スコープ内変数`undefined`が存在するのでそちらを優先する。そしてまだ定義されていないからエラーになる。
まき上げられて常に呼べる関数の巻き上げとは少し挙動が違うので注意。

### モジュールインポート
私がやってしまった例として

```js:import.js
import * as hoge from './hoge.js'

console.log(hoge) // undefined
const hoge=hoge.fromHTML(document.getElementById('hoge'));
```
`console.log`は変数の巻き上げによりundefinedになる。`const hoge`でhogeは定義されているが`fromHTML`は定義されてないため死んでるっぽいが死んでる旨のエラーをコンソールに出さずにその後の処理もされないので結構ハマった。
解決策は命名則をきちんとすることだろうがimport/export構文自体がややこしく難しい。

## 演算子
すべての演算子を列挙することはしないが幾つか取上げる。
詳しくはMDNで
https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Expressions_and_Operators

### `<==` `>==`
`===`,`!==`との絡みで存在するかと思ったが**存在しない**。

### **演算子
JavaScriptには**演算子がある、知らなかった:sweat:。そのまんばべき乗。`Math.pow(x,y)`もある。

### `typeof` `instanceof`
typeof演算子は単行演算子なので

```js
typeof tmp; // tmpの型の文字列
```
と使い返ってくるのは文字列です。
instanceofは2つの値を取るので

```js
tmp instanceof Date
```
Dateは日付に関するブラウザで定義されたインスタンスで、true/falseで返って来ます。
右辺にインスタンス化できないもの`number`等を入れると`ReferenceError`を飛ばします。
`HTMLElement`や`SVGElement`はインスタンス化できるもので例外は飛ばしません、`document.getElementById()`などで取ってきたものはHTMLElementのインスタンスです。

## 型判定
JavaScriptではオブジェクトの拡張性を利用したダッグタイピング的な利用が多いので型で判定するより、メソッドや変数を持っているかいないかで判断したほうが確実、それでも型判定したい時に

### typeof

```js:typeof.js
console.log(typeof true); // boolean                                                                
console.log(typeof 0);    // number                                         
console.log(typeof null); // object                 
console.log(typeof "null"); // string
console.log(typeof undefined); // undefined
(function(){
    const undefined="undefined";
    console.log(typeof undefined); // string       
})();
console.log(typeof void 0); // undefined
console.log(typeof function(){ return 0; }); // function
console.log(typeof ()=>{ return 0; }); // function
console.log(typeof class C{}); // function
console.log(typeof [ 1, 2, 3 ]); // object
```
存在(null/undefined)チェックにtypeofを使ってはいけない。存在判定は`x!=null`を使う
`undefined/null`以外の**プリミティブ型**のどれに属するか知りたい時に使うべし
関数は`function`となるが配列は`object`になる。
classも`function`になる、これはコンストラクタが関数として定義されているためと思われます。
またここから、関数とクラスだけ特別視しようとしてることが伺えます。

### Array.isArray
配列専用。JavaScriptの配列はObjectのキーが数字であるものでしか無いのでArrayの判定は非常に難しい。そのため専用のメソッドがある。JavaScriptの`isXXX`は一般には型判定用でないので注意。

### instanceof
インスタンスを判定する。右辺値によっては例外を飛ばすがそれを除けば大体これでOK

## 例外
JavaScriptで飛ばすなら`throw new`つけないと行番号が分からないのでつけるべき。
Webpackなどのビルドシステムを使うとtry/catch文が追加されるので例外が外に伝搬しない。例外キャッチを使いたければ同じファイル単位内でキャッチさせるべし！

# ブラウザ編
### 制御をユーザーに返す
```except.js
try{
   throw new Error(message);
}
catch(e){
   if( c!omfirm(e) ) throw e;
}
```
時と場合によってはユーザーに制御を返したいかも

## ブラウザAPIの一覧っぽいもの
| 名前　| 機能 | ライブラリなど |   備考  |
|:-----:|:-----------:|:----:|:----:|
| [WebGL](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API) | 3Dグラフィック| [three](https://threejs.org/)　| 言わずとしれた　|
| [SVG](https://developer.mozilla.org/en-US/docs/Web/SVG) | 2Dグラフィック | [snapsvg](http://snapsvg.io/), [d3](https://d3js.org/) | snapsvgが完全SVG用、d3はグラフ化ツール |
| [CanvasAPI](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API) | 2Dグラフィック | d3, [two](https://two.js.org/) | ラスタ形式（SVGはベクター形式）|
| [WebAudioAPI](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API) | 音楽 | | イマイチ決定打的なライブラリがない |
| [WebSocket](https://developer.mozilla.org/ja/docs/Web/API/WebSockets_API) | 双方向通信 | | サーバーはブラウザでは建てれない |
| [WebRTC](https://developer.mozilla.org/ja/docs/Web/API/WebRTC_API) | P2P | | [WebSocketとの違いなど](https://www.slideshare.net/yoshiakisugimoto9/webrtc-slide) |
| [XMLHTTPRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) | Ajax | [jquery](https://jquery.com/) | いらん子、Fetch使いましょう |
| [Fetch](https://developer.mozilla.org/ja/docs/Web/API/Fetch_API/Using_Fetch) | Ajax | | これでjqueryは本格的にいらない子になったはず |
| [FullscreenAPI](https://developer.mozilla.org/ja/docs/Web/Guide/DOM/Using_full_screen_mode) | フルスクリーンモード | [jquery.fullscreen](https://www.npmjs.com/package/jquery.fullscreen) | [名前が闇そのもの](https://w3g.jp/blog/html5_fullscreen_api),Fullscreen/FullScreen+ベンダープリフィックス|
| [file API](https://developer.mozilla.org/en/docs/Web/API/File) | ファイル操作系 | | `const fs=require('fs')`Node用 |
npmからsnagsvgを入れてWebpackで使うとバグってるらしい、[ローダーをセットしろとのことらしい](https://github.com/adobe-webplatform/Snap.svg/issues/341)。（斜め読みなので間違ってるかも）

## 個人的に有用だと思うnpmパッケージたち(一部違う)
個人的に面白そうだと思うパッケージたち、前に上げたライブラリはあげない。

| 名前　  | 機能                             |   備考    |
|:-----:|:--------:|:----:|
| mathjs | 数学関係、複素数、行列などをサポート | mathとは別物、微妙に惜しい子 |
| legendre-poly/gauss-quadrature | ガウスルジャンドル法用パラメーター | [原理は私の拙著で](http://qiita.com/kentaro1530/items/e1416aba24c0829dec4d) |
| fft/ml-fft | 高速フーリエ変換 | まあ当然あるわな |
| runge-kutta-4 | 4次のルンゲクッタ法 | 他にも似たようなライブラリはあった |
| math-digamma | [ディガンマ関数](https://ja.wikipedia.org/wiki/%E3%83%87%E3%82%A3%E3%82%AC%E3%83%B3%E3%83%9E%E9%96%A2%E6%95%B0) | |
| physic | 物理 | と思ったら中身はほぼからだった:sob: |
| [jsroot](https://root.cern.ch/js/) | 物理系グラフ化、元はC++ | npmにはない、ライセンスが微妙、ソースも微妙 |
妙に数学系が充実してる。実装まで見てないからどれだけ使えるかは不明だが。mathjsの複素数関係はC++とほぼ同じ結果を返してきたので問題なさそうである。legendre-poly/gauss-quadratureもREADME.mdはしっかりしてたので使えそう。

# Node編
## インタプリンタ終了
```js
> process.exit(0);
```
普通、`exit`か`quit`かそのカッコ`()`つきだけどnodeはprocessが必要。`crt+C`２回でも終了できる。

## main関数
```js:main.js
(()=>{
   console.log("hello world");
})();
```
即時実行しないと実行してくれない。クライアント側メインだと`window`のロード時とかで忘れがち。メインだけインデントをずらしたい時に使う。

## ファイル操作等
`fetch`、`XMLHTTPRequest`は存在しない。ブラウザAPIは存在しない。`fs`を使う。

```js:fs.js
const fs=require('fs');
const text=fs.readFileSync(argv.inputs[0], 'utf-8');
(処理)
```
コールバックとしても渡すことはできるが非同期実行になり(処理)との順番が保証されない。
そもそもHTTPRequest, fetchは通信系メソッドです。ブラウザはfile APIがあります。いや使う側はあんまり気にしないけどね

## importが使えない
requireを使う。

## Electron 
Nodeでブラウザの機能を使ってデスクトップアプリにするらしい。（調査中）

# 最後に
ブラウザ用とNodeだとだいぶ書き味が違う。大阪弁と秋田弁ぐらい違う、まあ日本語と英語までは違わないのでなんとかはできるが...。もうちょっとベンダーさんたちもNodeさんも仲良くしてください。:bow:
後、私は普段は似非C++erをしています。他言語から見ると自然に見える部分もあるかと思います。そういったコメントをいただきました。C++とJavaはやっぱり似てないなと再認識しました。
JavaScriptはコードが仕様書だ！！！を地で行ってる言語だと感じました。