本記事は一人アドベントカレンダー企画の一つです。
30代未経験エンジニアが25日後にJavaScriptをマスターするカレンダー
JAVASCRIPT.INFOを元にJavaScriptを勉強していき、そこで学んだ知識をアウトプットしていきます。
25日でJAVASCRIPT.INFOをやりきり、未経験エンジニアがJavaScriptをマスターする過程を投稿していきます。
14.1 Proxy と Reflect
知らない単語
- プロキシとは
- 企業などの内部ネットワークとインターネットの境界にあり、内部のコンピュータの代理としてインターネット上のコンピュータへ接続を行うコンピュータの事
学んだこと
Proxy はオブジェクトのラッパーであり、操作をオブジェクトへ転送し、必要に応じてその一部をトラップする
クラスや関数を含め、あらゆる種類のオブジェクトをラップすることができる
let proxy = new Proxy(target, {
/* traps */
});
1回使えば、 target の代わりに proxy を使う必要がある
プロキシは独自のプロパティやメソッドは持たず、トラップが指定されていれば操作をトラップし、そうでなければ target オブジェクトに転送する
- トラップできるもの
プロパティの読み取り、書き込み、削除(get、set、deleteProperty)
関数呼び出し(apply)
new 演算子(construct)
その他のトラップ
- プロキシの制限
組み込みオブジェクトの内部スロットへのアクセスはできない
プライベートクラスフィールドも同じく、内部的にはスロットを使用して実装されているので、プロキシされたメソッド呼び出しは、this としてターゲットオブジェクトをもつ必要がある
オブジェクトの等価評価「===」はインターセプトできない
感想
トラップできるものやプロキシの制限などルールを忘れてしまうと使用できないので、間違えないように覚えておく。
14.2 Eval: コード文字列を実行する
知らない単語
- minifierとは
- JavaScriptやCSSなどのコードを意味や動作を変えずに短い記述に変換し、伝送データ量を削減する事
学んだこと
組み込みの eval 関数を使うとコード文字列を実行することができる
let code = 'alert("Hello")';
eval(code); // Hello
eval されたコードは、外部変数を参照することができる
let a = 1;
function f() {
let a = 2;
eval('alert(a)'); // 2
}
f();
- “eval” を利用する
eval はあまり使用されない
理由は昔、JavaScript は今よりずっと弱い言語であり、多くのことは eval でしかできなかった
現在では様々なメソッドなどができ、eval を利用する理由はほとんど無い
感想
eval はほとんど使用されないので、頭の片隅に入れてぐらいで覚えておく。
14.3 カリー化と部分適用
知らない単語
- バリアントとは
- プログラムの実行条件を設定した値を管理するオブジェクトの事
学んだこと
this だけでなく、引数もバインドすることができる
例えば、関数 double を作るために、bind を使うと
let double = mul.bind(null, 2);
alert( double(3) ); // = mul(2, 3) = 6
alert( double(4) ); // = mul(2, 4) = 8
alert( double(5) ); // = mul(2, 5) = 10
mul.bind(null, 2) を呼び出すと、mul を呼び出す新しい関数 double が作成され、
null がコンテキストとして、2 が最初の引数として固定される
そして他の引数はそのまま渡される
これは既存の関数の一部のパラメータを変更することで新しい関数を作っている
- カリー化(Currying)
Currying は f(a, b, c) と呼び出し可能なものを f(a)(b)(c) として呼び出しできるように変換する
例えば、下記は2変数関数に対するカリー化を行う関数 curry を作っているもので、
f(a, b) を f(a)(b) に変換する
function curry(func) {
return function(a) {
return function(b) {
return func(a, b);
};
};
}
// 使い方
function sum(a, b) {
return a + b;
}
let carriedSum = curry(sum);
alert( carriedSum(1)(2) ); // 3
このように、実装はラッパーの連続である
- カリー化? 何のために?
高度なカリー化を使用すると、簡単に関数を通常呼び出し可能にしつつ、部分適用をすることができる
感想
既存の関数を修正したいが、同じ引数を何度も繰り返し指定したくない時にバインドはよく使う事になると思うので、他の方法も覚えつつ的確に使用していきたい。
14.4 参照型
知らない単語
- 無し
学んだこと
複雑なメソッド呼び出しは、 this を失う可能性がある
例えば、
let user = {
name: "John",
hi() { alert(this.name); },
bye() { alert("Bye"); }
};
user.hi(); // John
(user.name == "John" ? user.hi : user.bye)(); // Error!
となる
最後の行の三項演算子があり、メソッドは丸括弧 () ですぐに呼び出されるが、
呼び出しの内側の this の値は undefined になるのでエラーになる
- 参照型
参照型の値は、3つの値の組み合わせ (base, name, strict) である
base はオブジェクト
name はプロパティ
strict は use strict が効いている場合は true になる
参照型は言語の内部の型であり、
obj.method() 内の . のようなプロパティの読み取りでは、正確なプロパティ値ではなくプロパティ値とそれが取得されたオブジェクトの両方を保持する特別な 「参照型」の値を返す
なぜなら、後に続くメソッド呼び出し () がオブジェクトを取得しそこに this を設定するからである
感想
複雑なメソッド呼び出しは、 this を失う可能性があるという事で、できる限りシンプルに書く事が重要なのだという事がよくわかる。
14.5 BigInt
知らない単語
- 無し
学んだこと
BigInt は任意の長さの整数をサポートする特別な数値型である
bigint は n をリテラルの末尾に追加するか、文字列や数字などから bigint を作成する関数 BigInt を呼び出すことによって生成される
- 算術演算子
BigInt は通常の数値のように扱える
例えば、
alert(1n + 2n); // 3
alert(5n / 2n); // 2
注意点として
除算 5/2 は小数部分なしでゼロに向かって丸められた結果を返すので、すべての bigint に対する操作は bigint を返す
そしてbigint と通常の数値は混在できない
- 比較
比較も使える
alert( 2n > 1n ); // true
alert( 2n > 1 ); // true
注意点は、数値と bigint は異なる型なので、等価 == は使えるが、厳密等価 === は使えない
感想
BigInt は数値のように扱えるが、厳密には違うので、厳密等価 === が使えない事などをしっかり頭に入れておきたい。
最後に
プロキシ、カリー化、BigIntなど様々な事を学んだが、それぞれの特徴、役割をしっかり理解して先に進んでいきたい。