infoMore than 3 years have passed since last update.
【技術書まとめ】『JavaScript Primer』を読んだまとめ
Last updated at Posted at 2021-02-21
第一部: 基本文法
データ型とリテラル
-
typeof null
は object
となる
-
""
と''
は全く同じ
- 複数行の文字を入れるなら`
-
undefined
はただのグローバル変数で、undefined
という値を持っているだけ
演算子
- JSでは
10 + 0.5
は10.5
となる
> 数値は内部的にIEEE 754方式の浮動小数点数として表現されています
-
NaN === NaN
はfalse
になる
-
==
は使うべきではない
- 暗黙的な型変換をするから
1 + true; // => 2
- 使ってよい例外:
value == null
でnullとundefindを両方比較するとき
-
indexOf
は見つからないとき-1
を返す
-
if (~str.indexOf("木"))
で 0 となる
-
includes("木")
で見つけられる
-
""
(空文字列)はfalse
暗黙的な型変換
1 + "2"; // => "12"
-
Number.parseInt("1", 10);
で1をパースして10進数で取り出す
- 文字列とundefindは
NaN
となる
-
Number.isNaN(NaN);
でNaNとわかる
- sumでundefinedが入ると"NaN"になる
-
if (typeof value !== "number")
で防いだりする
- 空文字列は
typeof str === "string" && str.length === 0;
で判定する
-
const obj1 = { foo: 'bar' }; const obj2 = { foo: 'bar' }; console.log(obj1 === obj2);
関数と宣言
- 仮引数より呼び出し時の引数が少ない時、余ったものは
undefined
になる
-
prefix || 'デフォルト';
だと空文字列の時にもデフォルトが入ってしまう
- デフォルト引数にする
-
prefix ?? 'デフォルト';
にする
- まとめて入れたり、残りをまとめたり、まとめて出したりは
...array
でできる
- 関数の中でのみ使える
arguments[0]
-
function() { console.log(arguments[0]); }
のように引数が定義されてなくても使える
- Rest parameters が使えるならこれは使わない方がいい
-
function printUserId({ id }) { ... }
でuser.id
のidだけとれる
-
const { id } = user;
でもとれる
- 関数は関数オブジェクト
- アロー関数
- 常に名前がない
-
this
が決まっている
- 短く書ける
-
new
できない
-
argument
変数は使えない
- 同じ名前の関数宣言は上書きされる
- 引数となる関数はコールバック関数とよぶ
- コールバック関数を使う関数やメソッドを高階関数とよぶ
- JSでは関数とメソッドの違いはあまりない
文と式
条件分岐
- falsyな値
false
undefined
null
0
0n
NaN
-
""
(空文字列)
- falsyな値以外は真偽値に変換すると
true
となる
ループと反復処理
-
some
は一度でもtrue
が返ってくると反復処理を終了する
-
filter
はtrue
になった値だけを集められる
-
reduce
で反復処理ができる
-
array.reduce((前回の値, 現在の値) => { return 次の値; }, 初期値);
numbers.reduce((total, num) => { return total + num }, 0);
オブジェクト
- オブジェクトとはプロパティの集合
- プロパティ名と変数名が同じだと
{ name }
と省略して書ける
- プロパティ名に変数を使うときは
[]
を使う
- オブジェクトのプロパティを変数として使うときは分割代入する
const { ja, en } = languages;
- プロパティの削除は
delete obj.key1
- JSの
const
は再代入を防ぐだけ
- 値の変更はできてしまう
-
const obj = { key: "value" };
でもobj.key = "Hi!";
できる
- 変更防止は
Object.freeze
を使う
- 存在しないプロパティにアクセスすると
undefined
となる
- 例外は発生しない
- プロパティを持つか確認するには?
-
undefined
と比較する
-
in
演算子
if ("key" in obj) { ... };
-
hasOwnProperty
メソッド
if (obj.hasOwnProperty("key")) { ... }
- nullの可能性があるときには
obj?.a?.b
widget?.window?.title ?? "未定義"
-
[]
でも使える
languages?.[ja]?.[messageKey]
-
toString()
とString()
は同じ
- オブジェクトのプロパティ名は暗黙的に文字列に変換される
- オブジェクトを配列にする
-
Object.keys(obj)
でkeyの配列にする
-
Object.values(obj)
でvalueの配列にする
-
Object.entries(obj)
でkeyとvalueの配列にする
-
Object.assign
で複製やマージができる
-
const merged = Object.assign({}, objectA, objectB);
-
const merged = { ...objectA, ...objectB };
でもマージできる
-
const cloneObj = Object.assign({}, obj);
で浅い複製できる
プロトタイプオブジェクト
- 空オブジェクトでも
.toString()
を呼び出せる
-
Object.prototype
のメソッドを継承しているから
-
hasOwnProperty
とin
の違い
-
Object.create(null)
で本当に空のオブジェクトを作れる
- 昔は
Map
の代わりに使われていた
-
const obj = {};
でもobj["toString"]
でアクセスできてしまうから
配列
- 最後の要素へのアクセスは
array[array.length - 1]
でできる
- 存在しないインデックスへのアクセスは
undefined
になる
- 配列は常に
length
の数だけ要素を持っているとは限らない
- 疎な配列
-
const sparseArray = [1,, 3];
- 配列かどうか確認するには
isArray
-
typeof array
では"object"
となる
- 配列も分割代入できる
- 疎な配列があるから本当に未定義なものと区別できない
-
hasOwnProperty
で区別する
-
sparseArray.hasOwnProperty(1)
がfalse
となる
- どの位置にあるか知りたい
-
indexOf
とlastIndexOf
- オブジェクトには
findIndex
を使う
colors.findIndex((obj) => { return obj.color === "blue" });
- 条件に一致する要素を取得する
colors.find((obj) => { return obj.color === "white" });
- 指定範囲の要素を取得する
- 目当てのものが含まれているか確認する
-
inclues
- オブジェクトには使えない
-
some
colors.some((obj) => return obj.color === "blue"; });
- 追加と削除
- 結合したい
array.concat(["D", "E"]);
- flattenにしたい
-
newArray = ["X", "Y", "Z", ...array];
newArray = ["X", "Y", "Z"].concat(array);
- ES2019なら
flat(Infinity)
も使える
- 任意のインデックス要素を削除する
-
array.splice(インデックス, 削除する要素数)
- すべての要素を削除
-
array.length = 0;
とすると配列が空になる
- 注意する破壊的メソッド
- 非破壊でコピーする
array.slice()
-
array.concat()
- 指定の要素だけ集める
array.filter((currentValue, index, array) => { return currentValue % 2 == 1; });
-
reduce
array.reduce((累積値, 要素, インデックス, 配列) => { return 処理;}, 初期値)
文字列
- 分解したり繋げたりする
const strings = "赤・青・黄".split("・").join("、");
- 正規表現を使って抜き出す
const strings = str.split(/\s+/);
- "?"以降を抜き出す
-
const indexOfQuery = url.indexOf("?"); const queryString = url.slice(indexOfQuery):
- 文字列の検索
str.startsWith()
str.endsWith()
str.includes()
- 正規表現
const patternA = /パターン/フラグ;
-
const patternB = new RedExp("パターン文字列", "フラグ");
str.search()
-
"文字列".match(/パターン/);
- マッチしない時はnullを返す
-
/[a-zA-Z]+/g
で見つかっても最後までやる
-
/バターン1(パターン2)/
でカッコを取り出せる
- そのパターンにマッチするものがあるか調べる
- 基本はStringメソッドでやる
- 置換
str.replace("文字", "");
-
str.replace(/文字/, "");
- コールバックもできる
dateString.replace(/(\d{4})-(\d{2})-(\d{2})/, (all, year, month, day) => { ... };
- URLは
getResource()
- タグ付きテンプレート関数
- tag
template ${0} literal ${1}
;
-
function tag(strings, ...values) { ... };
String.raw()
文字列とUnicode
- JSでは「文字列は
Code Unit
が順番に並んだもの」として扱われる
- リンゴの絵文字の length は 2 になる
-
const codePoints = Array.from("リンゴ🍎"); // => ["リ", "ン", "ゴ", "🍎"]
- 正規表現のときは
u
をつける
-
const [all, fish] = "𩸽のひらき".match(/(.)のひらき/);
-
const [all, fish] = "𩸽のひらき".match(/(.)のひらき/u);
ラッパーオブジェクト
- なぜ型がメソッド呼び出しできるのか
- プリミティブ型は自動的にラッパーオブジェクトに変換されるからメソッド呼び出しできる
関数とスコープ
- 関数を定義する
- スコープとは
- 関数スコープ
function fn() { 関数スコープ };
- ブロックスコープ
- スコープチェーン
- グローバルスコープ
- グローバル変数
- ビルトインオブジェクト
-
undefined
やisNaN
-
Array
やRegExp
-
document
やmodule
- むやみにグローバルスコープへ変数定義しない
- 外側の変数が隠蔽されるから
- shadowing
- 関数を使って小さなスコープにして書く
-
var
は巻き上げする
- クロージャー
- 「外側のスコープにある変数への参照を保持できる」
- 静的スコープ
- メモリ管理の仕組み
- 解放はあくまでそのデータが参照されているかどうかで決まる
関数とthis
- 実行コンテキスト
- アロー関数以外の関数のthis
- ベースオブジェクト
-
call
、apply
、bind
で明示的に指定できる
- アロー関数の
this
非同期処理:コールバック/Promise/Async Function
- 同期的なブロック処理
- 非同期処理はメインスレッドで実行される
- 非同期処理も同期処理の影響を受ける
- 非同期なタイミングで実行される処理
- 普通に
try...catch
書くと非同期処理のエラーは処理できない
- エラーファーストコールバック
- 共通ルールの一つ
- 処理が失敗したら
error
にエラーオブジェクトを渡す
- 処理が成功なら2番目以降の引数に結果を渡す
fs.readfile("./example.txt", (error, data) => { if(error) { ...} else { ... } });
- Promise
- 成功したら
resolve
- 失敗したら
reject
const executor = (resolve, reject) => {};
-
then
メソッドで成功時と失敗時の処理を渡す
-
try...catch
を使わなくても例外がキャッチされる
-
catch
はpromise.then(undefined, onRejected)
のシンタックスシュガー
- Promiseの状態
- Fullfilled
- Rejected
- Pending
- FullfilledまたはRejectedではないとき
-
new Promise
でインスタンスを作成したとき
- 最初はPendingで、一度でも変化したらそこからは変わらない
-
resolve
した後のreject
は呼び出されない
-
resolve
した後にもう一度resolve
しても呼び出されない
-
Promise.resolve
- 最初からFullfilledな
Promise
インスタンスを作る
- Promiseチェーン
- 失敗時は一番近い失敗処理が呼び出される
- 途中の
then
は無視される
- 失敗を一度キャッチするとまたチェーンに戻る
-
catch
はFullfilled状態のPromiseインスタンスを作成するから
-
return Promise.reject(new Error("失敗"));
- 例外時も同じ
-
return
で値を返すと次のthen
へ引数として渡せる
-
Promise#finally
は必ず呼び出される
-
then
ごとに配列に値をpush
していく使い方もできる
-
Promise.all
で複数のPromiseもまとめられる
- どれを先に取得しても問題ないとき
- 一つでもRejectedとなったら失敗処理が呼び出される
-
Promise.race
- 1つでもSettled状態になれば次の処理をする
- 非同期処理のタイムアウトが作れる
- 一定時間経過しても処理が終わってないならエラーとする
-
timeout
とやりたい処理をPromise.race
の引数にする
- Async Function
async function doAsync() { return "値"; }
-
function doAsync() { return Promise.resolve("値"); }
- 同じ
- 必ず
Promise
インスタンスを返す
-
await
が使える
- どれにでもつけられる
async function fn1() {}
const fn2 = async function() {};
const fn3 = async() => {};
const obj = { async method() {} };
-
await
- 同期処理のように書ける
-
Promise
のresolveされた値がawait
の返り値になる
-
const value = await Promise.resolve(42);
- 例外があったらRejectedなPromiseが返る
- 非同期でもループ処理ができる
-
Promise.all
も使える
- Promiseを複数作ってから
Promise.all
に渡す
-
const promises = resources.map(function(resource) { return fetch(resource); });
const responses = await Promise.all(promises);
- Async Funtion の中でのみ使える
- 外の処理は止まらない
- UIなどの処理が止まってしまうから
- コールバック関数の時に注意
-
for
をforEach
に単純に変えられない
-
Promise.all
でまとめるか
Map/Set
- Map
- 初期値で渡せるのはエントリーの配列
new Map([["key1", "value1"], ["key2", "value2"]]);
-
size
で数がわかる
-
set
で追加する
-
get
で取り出す
-
has
でそのキーがあるか確認できる
-
delete
で削除する
-
clear
で全て削除する
-
keys
,values
が返すのは配列ではない
- マップとしての
Object
との違い
- デメリット
-
Object
はprototypeメソッドで意図しない動きをすることがある
- 昔は
Object.create(null)
のようにして使っていた
- キーは
Symbol
のみ
- メリット
- リテラル表現で作成しやすい
-
JSON.stringify
で変換できる
- 多くの場所で使われている
- WeakMap
- キーを弱い参照で持つ
- iterableではない
- 使い方
- イベントリスナーを管理する
- キャッシュとして一時的に計算結果を保存する
- Set
- 同じ値を入れると1つのみ格納される
- インデックスはない
-
forEach
が使える
- WeakSet
JSON
-
JSON.parse
-
json = [1, 2, 3]
なら返り値も配列
- パースできないと例外が投げられる
-
JSON.stringify
- 第二引数に
replacer
を渡せる
- keyがnullならundefinedにする処理
- ホワイトリストとしてkeyの配列を渡せる
- 第三引数にフォーマット時のインデントを設定できる
-
JSON.stringify(obj, null, 2)
ならスペース2個でインデント
- Symbolやundefinedは変換されない
- オブジェクト内に
toJSON
がある場合
Date
-
Date.UTC(2006, 0, 2, 15, 4, 5, 999)
-
getMonth
で取得すると+1
する必要がある
const mm = String(date.getMonth() + 1).padStart(2, "0");
- ほとんどライブラリを使う
Math
ECMAScriptモジュール
- なぜモジュールを使うのか
- 保守性
- 依存性の高いコードをまとめて、他への依存性を減らせる
- 名前空間
- 再利用性
- 名前つきエクスポート/インポート
export { foo };
export function bar() {};
import { foo, bar } from "./my-module.js";
- エイリアス
export { internalFoo as foo };
import { foo as myFoo } from "./named-export-alias.js";
- デフォルトエクスポート/インポート
- デフォルトエクスポートに名前をつけてインポートする
ECMAScript
- その機能がどのような経緯で入ったのかを調べる手段を持っておく
- その機能が何を解決するために導入されたのかを知る
- 調べたいと思ったときに調べることができるように、調べ方を知っておくことが重要
Register as a new user and use Qiita more conveniently
- You get articles that match your needs
- You can efficiently read back useful information
- You can use dark theme
What you can do with signing up