JavaScript
Node.js
tips
雑記

JavaScript Tip集(随時更新)

More than 1 year has passed since last update.

この記事の内容

個人的に感じた。JavaScriptの罠、有用な点など、随時更新予定

一般編

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

var, let, const

var

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

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

要はvarは使うな。

const

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

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つのプリミティブ型

booleannumberstringsymbolobjectnullundefined

boolean/string

真偽値/文字列

number

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

let num=0.5;
num++; // num=1.5

内部的にはすべてIEEE 754の64bit浮動点小数として扱われる。
int(整数)、double(浮動点小数)は存在しないがどちらとして扱いたいかが重要なの時は形名を書くときはint/doubleで書くことを薦める。

symbol

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

object

JavaScriptの最大の特徴functionArrayもオブジェクトの一種です。

プロトタイプベース

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は予約語ではないらしい。???nullはリテラル同じくリテラルのtruefalseも代入出来なかった。

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:と思うと死ぬ。

strange.js
{
  console.log(undefined);
  const undefined=0;
}

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

モジュールインポート

私がやってしまった例として

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演算子は単行演算子なので

typeof tmp; // tmpの型の文字列

と使い返ってくるのは文字列です。
instanceofは2つの値を取るので

tmp instanceof Date

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

型判定

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

typeof

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 3Dグラフィック three  言わずとしれた 
SVG 2Dグラフィック snapsvg, d3 snapsvgが完全SVG用、d3はグラフ化ツール
CanvasAPI 2Dグラフィック d3, two ラスタ形式(SVGはベクター形式)
WebAudioAPI 音楽 イマイチ決定打的なライブラリがない
WebSocket 双方向通信 サーバーはブラウザでは建てれない
WebRTC P2P WebSocketとの違いなど
XMLHTTPRequest Ajax jquery いらん子、Fetch使いましょう
Fetch Ajax これでjqueryは本格的にいらない子になったはず
FullscreenAPI フルスクリーンモード jquery.fullscreen 名前が闇そのもの,Fullscreen/FullScreen+ベンダープリフィックス
file API ファイル操作系 const fs=require('fs')Node用

npmからsnagsvgを入れてWebpackで使うとバグってるらしい、ローダーをセットしろとのことらしい。(斜め読みなので間違ってるかも)

個人的に有用だと思うnpmパッケージたち(一部違う)

個人的に面白そうだと思うパッケージたち、前に上げたライブラリはあげない。

名前  機能 備考
mathjs 数学関係、複素数、行列などをサポート mathとは別物、微妙に惜しい子
legendre-poly/gauss-quadrature ガウスルジャンドル法用パラメーター 原理は私の拙著で
fft/ml-fft 高速フーリエ変換 まあ当然あるわな
runge-kutta-4 4次のルンゲクッタ法 他にも似たようなライブラリはあった
math-digamma ディガンマ関数
physic 物理 と思ったら中身はほぼからだった:sob:
jsroot 物理系グラフ化、元はC++ npmにはない、ライセンスが微妙、ソースも微妙

妙に数学系が充実してる。実装まで見てないからどれだけ使えるかは不明だが。mathjsの複素数関係はC++とほぼ同じ結果を返してきたので問題なさそうである。legendre-poly/gauss-quadratureもREADME.mdはしっかりしてたので使えそう。

Node編

インタプリンタ終了

> process.exit(0);

普通、exitquitかそのカッコ()つきだけどnodeはprocessが必要。crt+C2回でも終了できる。

main関数

main.js
(()=>{
   console.log("hello world");
})();

即時実行しないと実行してくれない。クライアント側メインだとwindowのロード時とかで忘れがち。メインだけインデントをずらしたい時に使う。

ファイル操作等

fetchXMLHTTPRequestは存在しない。ブラウザAPIは存在しない。fsを使う。

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はコードが仕様書だ!!!を地で行ってる言語だと感じました。