コピペで済ませている人が驚いたJavaScriptの常識

[JavaScript Advent Calendar 2017](https://qiita.com/advent-calendar/2017/javascript) 15日目の記事です。

本格的に学んだことはありませんでしたが、他人の書いたコードや、ググって出てきたコードのコピペでいい感じに動いてくれるため、そこまできちんと勉強していなかったjavascriptですが、「JavaScript本格入門」を読んで勉強し直したところ、驚くような挙動が沢山見つかったのでまとめてみました。

# 開発consoleにコピペで実行できる

~~いきなりコピペかよ~~

chromeとsafariで確認。正直これが一番の驚き。
ちょっとしたコードなら手元で確認できます。

piaza.ioみたいな環境でjavaを動かして喜んでいましたが、
JavaScriptはネットに繋がってないブラウザで検証できちゃいますね。

```js
let test = "hello";
test += " world";
console.log(test);
```

※この記事で紹介するコードも基本的にコンソールにコピペで検証できるようにしてあります

# 定義された変数をガンガン上書きできる

例えばjQueryなどを利用しているサイトなどのjQueryや$などのオブジェクトを上書きすることができます。

利用したサイト:https://jquery.com

```js
console.log($("title").html());//jQuery
var $ = "上書き"
console.log($("title").html());//TypeError: $ is not a function. (In '$("title")', '$' is "上書き")//上書き後の$オブジェクトはjQueryとして利用できない。
```


複数のライブラリなどを動かした際に名前の衝突などが心配です。
ただし、ES6で導入されたlet,constを利用すればこの動作は防げます。

# オブジェクトに連想配列のようなアクセスができる

特に何も用意しなくてもこのようなことができることに驚きました。

```js
var person= {name:"Yamada tarou", age:"18", sex:"man"}

//javaっぽくフィールドにアクセスする感じで・・・
console.log(person.name);//Yamada tarou
console.log(person.age);//18
console.log(person.sex);//man

//連想配列のようにアクセス！
console.log(person["name"]);//Yamada tarou
console.log(person["age"]);//18
console.log(person["sex"]);//man
```

ちなみに後述のES6ではMapオブジェクトが用意されています。

```js
let map = new Map();
map.set('test','テスト');
map.set('bug','バグ')

console.log(map.get('test'));//テスト
console.log(map.get('bug'));//バグ
console.log(map.size);//2
```

このMapと標準のオブジェクトでは以下の違いがあります。



## Mapオブジェクトは任意の型でキーを設定できる

オブジェクトではキーとして利用できるのは文字列だけですが、
Mapオブジェクトでは任意のオブジェクトをキーとして利用することができます

## Mapオブジェクトはサイズを取得可能
Mapオブジェクトではsizeプロパティを使って登録された要素の数を取得できます。
オブジェクトにはこのような仕組みがないので自分でforループなどでカウントする仕組みを作る必要があります。

## オブジェクトを連想配列っぽく利用すると余計な要素が最初から存在する

personの例でいうと身長(height)は定義していないのでundefinedになってしまいますが、Objectオブジェクトが保持しているtoStringなどはundefinedになりません。

```js
person["height"];//undefined
person["toString"];//[native code]
```

# 配列がstack queのように利用できる

あまりスタックやキューのようなデータ構造が必要になることは少ないのですが、
配列だけでこのようなことができることに驚きました。

```js
var data = [1,2,3];
data.push(15);
data.push(20);
data.push(25);

console.log(data); //[1, 2, 3, 15, 20, 25] 
console.log(data.pop()); //25
console.log(data.shift()); //1
console.log(data); // [2, 3, 15, 20]
```


# 多次元配列が存在しないが強引に作成可能
paizaのスキルチェックで必要になり、多次元配列について調べていて気づきました。
まずこのこと自体に驚いたのですが、
配列の中に配列リテラルを詰め込むことで強引に多次元配列を作ることができさらに驚きました

```js
var data = [[1,2,3],[4,5,6],[7,8,9]];
console.log(data[1][2])//6
```

# JSONはJavaScriptのソースコードとして解釈可能

JavaScriptに触れるまでJSONはcsv,xmlなどと同様のただのデータ型式だと思っていたのですが、JavaScriptのオブジェクトリテラルの構文が元になっていること、
そしてJSON自体がJavaScriptのコードとして解釈可能なことを知ってさらに驚きました。

```js:evalでJavaScriptとして評価
var jsontext = '{"name": "John", "age": 45}';//JSONの文字列

eval('var jsontest = '+jsontext);
console.log(jsontest.name)//John
console.log(jsontest.age)//45
```

※JSONのパースにevalは一般的には使ってはいけないので、
代わりにJSON.parseを使いましょう。

```js:parseを使った場合
var jsontext = '{"name": "John", "age": 45}';//JSONの文字列
var jsontest =  JSON.parse(jsontext);
```

# ==と===の違い

==より===の方が厳密に比較します。
==では型が違っていても比較結果がtrueとなることがあります。

```js
1=='1'//true
1==='1'//false
```

## switch命令では内部で===を利用している


```js
var num = '1'
switch(num){
  case 1:
    console.log('数字の1です');
　　 break;
  case '1':
    console.log('文字の1です');
    break;
  default;
    console.log('その他');
    break;
}
//文字の1です
```

# strictモード
よくない記法の混入を防いでくれます。
例えばvarの省略などを防げます。
※varはつけ忘れるとグローバルスコープとなる

```js
(function hoge() {
   'use strict';  
   test = "test"//Uncaught ReferenceError: test is not defined
}());
```

曖昧な書き方やよくない記法などを制限してコードの品質を高めることができます。
このような仕組みは積極的に利用するべきだと思います。

# スコープが関数 or Globalしかない
後述するES6になるまで、javascriptにはブロックスコープという概念が存在しませんでした。varで宣言した変数はその関数の範囲の中だけで有効になり、varを省略するとグローバルスコープとなってしまいます。

# ES6
「JavaScript本格入門」を読むまでES６の存在は感知しておりませんでした。
まだまだ対応していないライブラリや環境などもあるようですが、標準的な仕様を作ろうという取り組みは素晴らしいと思います。

# トランスパイラ、altJSの存在
型宣言が出来なかったり、アクセス修飾子が存在しないため大規模なコーディングに使いにくいJavaScriptですが、両者を備えた別言語で一旦書いたものをJavaScriptに変換して利用する、altJSという概念に驚きました。

 - TypeScript
 - CoffeeScript
 - Dart

またトランスパイラを利用することで、ES6で書いたものを以前の環境で動かすために、ES6以前のコードに変換することができます。

個人的にはアクセス修飾子など、構文が用意されていない仕組みを頑張ってトリッキーに実現するのではなく、構文が用意されているTypeScriptなどで記述してJSのコードへ変換するのが間違いなどが減り、コードもわかりやすくて良いと思いました。

# 最後に

私はJava,vbなどの保守を中心に扱うSIerであり、フロントエンドエンジニアではないため、JavaScriptを専属として触ることはほとんどありませんが、ちょっとしたテキスト置換などのスクリプトを書くには便利な言語だなという印象を持ちました。

また最近は仕事でもプログラミング自体をする機会が減っているため、仕事のためのコーディングではなく、自分のためのコーディングに利用するためにJavaScriptをこれからも学んでいきたいと思います

# 参考

[改訂新版JavaScript本格入門](https://www.amazon.co.jp/改訂新版JavaScript本格入門-モダンスタイルによる基礎から現場での応用まで-山田-祥寛/dp/477418411X)