Javascript
基本
変数が配列かどうか判定する
Array.isArray()
を使う。
const arr = [1, 2, 3]
Array.isArray(arr)
delete: オブジェクトから指定したプロパティを削除する
オブジェクトからプロパティを削除するにはdelete
を使う。
delete
はプロパティの削除に成功するとtrue
、失敗するとfalse
を返す。
オブジェクト自体をdelete
しようとすると失敗し、strict モードではエラーとなる。
const hoge = { a: 10, b: 20 };
delete hoge.a;
console.log(hoge); // { a: 10 }
// オブジェクト自体を削除することはできない
delete hoge; // false
delete []; // false
// strictモードではオブジェクト自体をdeleteするとエラー
("use strict");
delete hoge; // error
配列の要素に対してdelete
すると、該当要素がundefined
となる。
const hoge = ["a", "b", "c"];
delete hoge[0];
console.log(hoge); // [undefined, 'a', 'b']
単にプロパティへundefined
を代入するのとは違い、delete
でプロパティを削除するとプロパティ自体が消える。そのため、in
演算子やhasOwnProperty()
の結果がfalse
になる。
Ref:
https://stackoverflow.com/a/14967568
instanceof: オブジェクトが指定したコンストラクタを持つか判定
instanceof
は、左辺のオブジェクトが右辺のコンストラクタ関数をもつか判定する。
console.log(new String("hoge") instanceof String); // true
すべての javascript オブジェクトはObject()
コンストラクタを持つため、どのオブジェクトに対しても*** instanceof Object
はtrue
になる。
console.log({ a: 1, b: 2 } instanceof Object); // true
console.log({} instanceof Object); // true
console.log([] instanceof Object); // true
// プリミティブ型はオブジェクトではないのでfalseになる
console.log(1 instanceof Object); // false
console.log("a" instanceof Object); // false
console.log(true instanceof Object); // false
in: メンバがオブジェクトに存在するか判定
in
は、指定したメンバ(プロパティ or メソッド)が指定したプロパティに存在するか判定する。
console.log("a" in { a: 1 }); // true
console.log("b" in { a: 1 }); // false
addEventListener: イベントリスナを登録する
第二引数でイベント伝搬の向きを指定できる。
- true: キャプチャフェーズで実行
- false(デフォルト): バブリングフェーズで実行
const dom = document.getElementById("a");
dom.addEventListener(
"click",
() => {
console.log("clicked");
},
true
);
window オブジェクト
window オブジェクトは以下のプロパティを持つ。
- console
- document
- indexedDB
- location
- localStorage
- navigator
- worker
window.open()
新しいウィンドウを開いて指定した URL を表示する。
// 第二引数はウィンドウの名前。<a>や<form>で参照できる
const newWindow = window.open("localhost:1111", "windowName");
postMessage()
で他のウィンドウへメッセージを送信できる。
// 開いたウィンドウへメッセージを送信する
newWindow.postMessage("message", "localhost:1111");
メッセージの受信側でmessage
イベントにリスナを追加することで受信したメッセージに対して処理ができる。
window.addListener("message", e => {
// 受信したメッセージ
console.log(e.data);
// 送信元のオリジン ex) localhost:1111
console.log(e.origin);
// 送信元のwindowオブジェクト
console.log(e.source);
});
ウィンドウ操作
- close(): ウィンドウを閉じる
- moveBy(): ウィンドウを相対値で移動する
- moveTo(): ウィンドウを絶対値で移動する
- open(): ウィンドウを開く
- resizeBy(): ウィンドウを相対値でリサイズする
- resizeTo(): ウィンドウを絶対値でリサイズする
DOM イベント
DOM イベントはユーザ操作だけでなく、dispatchEvent()
を使って実行することもできる。
window.dispatchEvent(new Event("click"));
Event
オブジェクトは以下のプロパティを持つ。
プロパティ名 | 説明 |
---|---|
target | イベント発生元のオブジェクト |
timeStamp | イベントが発生した時間(ミリ秒) |
type | 発生したイベントの種別 |
Event.stopPropagation()
イベントの伝搬を中止する。
hoge.addEventLIstener("click", ev => {
console.log("clicked");
ev.stopPropagtion();
// これ以降親・子要素でのイベント伝搬がされない
});
typeof: データ型を表す文字列を返す
typeof
は、指定した値のデータ方を表す文字列を返す。
返す値は以下のいずれかで、オブジェクトを指定すると必ず'object'
が返る。
- "number"
- "string"
- "boolean"
- "object"
console.log(typeof 1); // "number"
console.log(typeof ""); // "string
console.log(typeof true); // "boolean"
console.log(typeof {}); // "object"
console.log(typeof []); // "object"
console.log(typeof new String()); // "object"
-
演算子を使うと自動的に数値に変換される
数字同士で// 50
console.log("100" - "50");
==
で文字列と真偽値、数値を比較すると、文字列は自動的に数値か真偽値に変換される
==
と===
の違いを簡単に整理すると以下のようになる。
==
: (文字列の場合は)型変換ありで比較する===
: 型変換なしで比較する
console.log("100" == 100); // true
console.log("100" === 100); // false
DOM 関連
指定した要素以外のマウスイベントのみ処理する
コンテキストメニューを閉じる処理などに使える。
指定した要素でstopPropagation()
することで、指定した要素をクリックしたときはClick inner!
のみ表示され、要素外をクリックしたときはClick outer!
のみ表示される。
const handleExceptedElementClick = (e: MouseEvent) => {
console.log('Click inner!')
e.stopPropagation()
}
useEffect(() => {
const handleOuterElementClick = (e: MouseEvent) => {
console.log('Click outer!')
}
document.addEventListener('click', handleOuterElementClick)
return document.removeEventListener('click', handleOuterElementClick)
}, []);
DOM の絶対位置を取得
const e: HTMLElement = document.getElementById("hoge");
var rect = element.getBoundingClientRect();
console.log(rect.left + window.pageXOffset); // x座標(絶対座標)
console.log(rect.top + window.pageYOffset); // y座標(絶対座標)
console.log(rect.width); // 幅
console.log(rect.height); // 高さ
Ref: http://phiary.me/javascript-get-bounding-client-rect-absolute-position/
マウスイベント位置の取得
Reactの例:
const handleCanvasClick = (e: React.MouseEvent) => {
console.warn(e.nativeEvent.offsetX, e.nativeEvent.offsetY)
}
return <div onClick={handleCanvasClick} />
Ref:
https://tech-dig.jp/javascript-click-position/
ReactConvaの例:
const handleClick = (e: KonvaEventObject<MouseEvent>) => {
const [eventX, eventY] = [e.evt.offsetX, e.evt.offsetY]
}
HTML 要素の実際のスタイルを取得
style に指定した色ではなく実際に表示している色を取得する例:
const el = node as HTMLElement;
console.log(window.getComputedStyle(el, null)["backgroundColor"]);
// rgb(33, 33, 33)
Ref:
https://stackoverflow.com/q/46336002
rgb(x, x, x)を Hex 形式に変換
function rgb2hex(rgb) {
rgb = rgb.match(
/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i
);
return rgb && rgb.length === 4
? "#" +
("0" + parseInt(rgb[1], 10).toString(16)).slice(-2) +
("0" + parseInt(rgb[2], 10).toString(16)).slice(-2) +
("0" + parseInt(rgb[3], 10).toString(16)).slice(-2)
: "";
}
Ref:
https://jsfiddle.net/Mottie/xcqpF/1/light/
snippet
bind
で部分適用
普通に実装するよりシンプルに書ける。
const add = (x: number, y: number) => x + y
const add10 = add.bind(null, 10)
console.log(add10(5)) // 15
Ref:
https://qiita.com/hosomichi/items/e11ad0c4ea79db2dee84#bindをつかった部分適用
カウントアップで文字列を生成
const stringRefcount = () => {
let id = 0
return () => (++id).toString(36)
}
文字列から前後の空白と連続した空白を取り除く
str.trim().replace(/\s+/g, '')
配列内の特定の要素のプロパティを変更する
const obj1 = { id: 1, a: "foo", b: 10 };
const obj2 = { id: 2, a: "bar", b: 20 };
const arr = [obj1, obj2];
// 変更オブジェクト
const mod = { a: "hoge", b: "fuga" };
// 変更対象オブジェクトを取得
const target = arr.find(item => item.id === 1);
// 変更オブジェクトの内容で更新
for (let propName in mod) {
target[propName] = mod[propName];
}
// [ {id: 1, a: 'hoge', b: 'fuga'}, {id: 2, a: 'bar', b: 20} ]
console.log(arr);
range()関数を作る
// [...Array(n).keys()] はjsだと動くけどtsだと動かない
const range = (count: number) => Array.from(Array(count).keys());
range(10).forEach(i => console.log(i))
ミリ秒待つ
const sleep = msec => new Promise(resolve => setTimeout(resolve, msec));
await sleep(1000);
await
したい
ルートで(async () => {
// ...
// await hoge()
})();
タイムスタンプ取得
Date.now();
Promise
コールバックで非同期する代わりに同期できる
// `file`と、処理結果のコールバックを受け取る関数があるとする
const load = (file, onSuccess, onFailure);
// Promise化
const loadPromise = (file = new Promise((onSuccess, onFailure) =>
load(file, onSuccess, onFailure)
));
// 同期関数として使う
const result = await loadPromise("hoge.txt");
ファイルダウンロード
downloadjs
を使う。
https://github.com/rndme/download
yarn add downloadjs
CSV ダウンロード
papaparse
と組み合わせて、js オブジェクトや JSON を csv に変換してからダウンロードする。
import Papa from "papaparse";
import download from "downloadjs";
const csv = Papa.unparse([{ hoge: 1, fuga: "a" }, { hoge: 2, fuga: "b" }]);
download(csv, "file.txt", "text/plain");
ファイル読み込み
CSV
accept
属性で選択可能なファイルを指定できる。
http://html5.cyberlab.info/elements/forms/input-accept.html
ex) .csv
のみ選択させる
<input type="file" accept=".csv" />
text/csv
は効かないので注意。
csv ファイルのパーサーはpapaparse
を使うと楽。
yarn add papaparse
import Papa from "papaparse";
// `header: true`を設定するとインデックスじゃなく列名をキーとしてアクセスできる
const persePromise = file => new Promise((complete, error) => Papa.parse(file, {complete, error, header: true}))
const Uploader = () => {
const handleChangeFile = e => {
const file = e.target.files[0];
const res = await persePromise(file)
console.log("Finished:", results.data);
};
return (
<div>
<input
type="file"
className="inputFileBtnHide"
onChange={handleChangeFile}
/>
</div>
);
};
Service worker
Hello World
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<script src="./index.js"></script>
<title>Document</title>
</head>
<body>
<p>Hello Service Worker.</p>
</body>
</html>
index.js
if ("serviceWorker" in navigator) {
window.addEventListener("load", function() {
navigator.serviceWorker.register("/sw.js").then(
function(registration) {
// Registration was successful
console.log(
"ServiceWorker registration successful with scope: ",
registration.scope
);
},
function(err) {
// registration failed :(
console.log("ServiceWorker registration failed: ", err);
}
);
});
}
sw.js
self.addEventListener("install", function(event) {
console.log("Service Worker installing.");
});
self.addEventListener("activate", function(event) {
console.log("Service Worker activating.");
});
ブラウザスレッドとのメッセージ送受信
ワーカーへ送信
ブラウザ側:
const channel = new MessageChannel();
navigator.serviceWorker.controller.postMessage("Hello, world", [channel.port2]);
ワーカー側:
self.addEventListener("message", function(event) {
console.log("received...", event.data);
});
ブラウザへ送信
ブラウザ側:
channel.port1.onmessage = e =>
e.data.error
? console.log(e.data.error)
: console.log(`I got a message from ws. ${JSON.stringify(e.data)}`);
ワーカー側:
self.addEventListener("message", e =>
event.ports[0].postMessage({
msg: "Hey I just got a push from you!",
data: event.data
})
);
ワーカーはイベント契機でしか動けないので、この例ではブラウザからメッセージを受信したら、同じメッセージをブラウザに送信し返すようになっている。 実際は、ブラウザからメッセージを受け取りワーカーでバックグランドで重い処理を実行、結果をメッセージにしてブラウザに返す。という感じになりそう。
Worker 独自の構文
importScripts
ワーカーで IndexedDB を操作
ライブラリにdexie.js
を使う。
ワーカーではimport
, require
の代わりにimportScripts
が使える。
importScripts("https://unpkg.com/dexie@2.0.3/dist/dexie.js");
FAQ
Cannot read property 'postMessage' of null
Service worker が更新できてないのが原因っぽい?
self.clients.claim()
を呼ぶと強制的に最新にできるらしい。
それでもダメなら DevTool でApplication -> Service Worker -> Update
する。
self.addEventListener("activate", function(event) {
console.log("activate!!");
self.clients.claim();
});