# JavaScript
# Functions
- アロー関数は無名関数である。名前のついた関数を作る場合は function を使う。
# Arguments
多く渡しても、少なく渡してもエラーは発生しない
足りない分は undefined となり、余った分は何事もないかのように振る舞う
スプレッド演算子が便利
function hoge(...aaa) { console.log(aaa); } hoge(1, 2, 3, 4, 5); //=> (5) [1, 2, 3, 4, 5] function hoge(...aaa) { console.log(...aaa); } hoge(1, 2, 3, 4, 5); //=> 1 2 3 4 5
# this
this
=== the Object that is executing the current function- つまり、ファンクションを実行しているオブジェクトを指す
- 関数の宣言された場所ではなく、関数の呼び出され方によって変わる
# Method として呼び出された場合
メソッドとして呼び出された場合は、this はそのオブジェクトを指す。 メソッドとして呼び出すとは、オブジェクトのプロパティとして関数を実行すること。
const obj = {
name: 'たなか',
speak() {
console.log(this.name);
},
};
obj.speak(); //=> たなか
// obj.speak.apply(obj) と等価
# Function として呼び出された場合
Function として呼び出された場合は、this は window / global を指す。(callback として渡される Anonymous Funciton を含む)
function a() {
console.log(this);
}
a(); // => window / global
変数に代入した場合も同様
const a = function() {
console.log(this);
};
a(); // => window / global
あるオブジェクトのメソッドを変数に代入した場合も同様
const obj = {
say: function() {
console.log(this);
},
};
const someVar = obj.say;
someVar(); // => window / global
コールバックや IIFE も同様
const obj = {
say() {
(function() {
console.log(this);
})();
},
};
obj.say(); // => window / global
# this の束縛
this は呼び出した時の状況によって参照先が変化してしまう。apply
, call
, bind
, アロー関数を使用することにより、常に指定したものを this として動作させることができる。
# constructor
コンストラクタから生成されたオブジェクトは、生成に使用したコンストラクタ関数を保持している。
function TestConstructor() {}
const test = new TestConstructor();
test.constructor; // => ƒ TestConstructor() {}
この constructor は、コンストラクタ関数の prototype として存在するもの。
TestConstructor.prototype.constructor; // => ƒ TestConstructor() {}
instanceof と異なり、コンストラクタの種類が判定できるため「出所不明」なオブジェクトの詳細を調べる際に使える。
const a = [];
const b = {};
const c = function() {};
a.constructor; //=> ƒ Array() { [native code] }
b.constructor; //=> ƒ Object() { [native code] }
c.constructor; //=> ƒ Function() { [native code] }
// 自作コンストラクタ(無名関数にすると名前は調べられないので注意)
const Myfunc = function Myfunction() {};
const func = new Myfunc();
func.constructor; //=> ƒ Myfunction() {}
# リテラル
データ型に格納できる値そのもの、または値の表現方法のこと
- 数値リテラル
- 文字列リテラル
- 配列リテラル
- オブジェクトリテラル
# null と undefined
- 「null」 は null を設定した状態。設定しない限り存在しない。
- 「undefined」は未定義、何も設定していない状態。
# if 文で false と判定される条件
- undefined
- null
- 0
- 空文字("")
- false
- NaN
# typeof
タイプを調べる時に使う。プリミティブにのみ使用すべきである。配列や null が object として判定されるなど、不思議な側面があるため。
# instanceof
- オブジェクトが何のコンストラクタから生成されたかを判定する。
- instanceof 演算子はプロトタイプチェーンを辿ってチェックを行うため、
something instanceof Object
は原則として true となる。(全てのオブジェクトは Object から派生しているため)
const a = {};
const b = [];
const c = function() {};
a instanceof Object; //=> true
b instanceof Array; //=> true
c instanceof Function; //=> true
# Symbol
- プリミティブに分類される
- Symbol() コンストラクタから作成する。new は不要。
- 作成されたシンボルは必ずユニークとなる。
- オブジェクトの Key として使うことができる。文字列ではないのでブラケットをつけるのを忘れずに。
const obj = {};
const HOGE = Symbol();
typeof HOGE === 'symbol'; // => true
obj[HOGE] = 123;
obj.HOGE = 999; // or obj['HOGE'] = 999;
obj; // => {HOGE: 999, Symbol(): 123}
# Map / Set
- Map
- key-value ペアを扱う
- key となるオブジェクトに対し、オブジェクトを汚さずに情報を付加できる
- Set
- 重複のないデータセットを扱う
いずれも、key には primitives と object を使うことができる。
# WeakMap / WeakSet
基本的には Map / Set と同じ。異なる点は以下の通り。
- key はオブジェクトである必要がある。プリミティブは使えない。
- key の一覧を取得する方法がない。
- key として設定されているのオブジェクトへの参照が一つもなくなった時点で、外部から情報を取得する手段がなくなるため、ガベージコレクションの対象になる。(=弱い参照)
vm = new WeakMap();
let key = {}; // キーにはオブジェクトを使用する
wm.set(key, 100); // keyに100を関連付ける
wm.get(key); // => 100
key = { some: 'new object' }; // 参照元が一つもなくなる
wm.get(key); // => undefined
# URI エンコード
エンコードが必要な部分ごとに encodeURIComponent
をかけた上で結合し、URI を完成させること。
firebase storage のダウンロードリンクを作成する際によく使う。
encodeURIComponent('post/filename.jpg');
// => "post%2Ffilename.jpg"
# Object のクローン
spread(...
)を使ってオブジェクトをコピーしても、2 階層目以下の変数は依然同じオブジェクトを指し示す。
これを回避するには lodash のcloneDeep
などが必要となるが、手っ取り早くやるには下記のようにするとよい。
var oldObject = {
address: {
street: 'Station Road',
city: 'Pune',
},
};
var newObject = JSON.parse(JSON.stringify(oldObject));
newObject.address.city = 'Delhi';
console.log(oldObject); // => Pune
console.log(newObject); // => Delhi
# Async / Await の落とし穴
forEach
の中ではawait
が効かない。
for
, for-of
, for-in
を使え。
# Generator
通常のファンクションと似ているが、処理途中の段階で値を取り出す(yield)ことができること、その状態を保持したまま何度も呼び出して処理を継続できる点が異なる
function* generator() {
for (i = 0; i < 10; i++) {
yield i;
}
}
for (i of generator()) {
console.log(i);
}
// => 123456789