js3 データ型
問題一覧
1
String.fromCodePoint と str.codePointAt はサロゲートペアを正しく扱う稀なメソッドです
2
マーク文字を付与した際に比較を確実に行うために正規化する。 具体的には、正規化されると、一つの文字として扱われるようになる 詳細は以下 多くの言語では、上/下にマークを持つ基本文字で構成される記号があります。 例えば、文字 a は àáâäãåā のベースの文字です。最も一般的な “複合” 文字は、UTF-16テーブルに独自のコードを持っています。 任意の複合文字をサポートするため、UTF-16 ではいくつかのユニコード文字を使うことができます。ベース文字とそれを “装飾” する1つまたは複数の “マーク” 文字です。 以下のように Sのベース文字に対し、マーク文字を複数付与できる。 let s1 = 'S\u0307\u0323'; // Ṩ, S + 上のドット + 下のドット let s2 = 'S\u0323\u0307'; // Ṩ, S + 下のドット + 上のドット alert( `s1: ${s1}, s2: ${s2}` ); alert( s1 == s2 ); // false (文字は同一に見えますが) これを解決するために正規化が用意された。
3
str.normalize() で実装されています。 記号 Ṩ の場合 alert( "S\u0307\u0323".normalize() == "S\u0323\u0307".normalize() ); // true 例の場合、normalize() は実際に3つの文字の並び(ベース文字とマーク文字2つ)を1つの文字 \u1e68 (S と2つのドット)にまとめています。 alert( "S\u0307\u0323".normalize().length ); // 1 alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true
4
str.trim() – 文字列の最初と最後のスペースを除去します。 str.repeat(n) – 文字列を n 回繰り返します。
5
JavaScript では文字列はイミュータブル(不変)なので、最初の文字を “置換” することはできません。 しかし、既存のものをベースに、最初の文字が大文字化された新しい文字列を作ることはできます。: let newStr = str[0].toUpperCase() + str.slice(1); が、そこには少し問題があります。str が空の場合、str[0] は未定義です。なのでエラーになります。 function ucFirst(str) { if (!str) return str; return str[0].toUpperCase() + str.slice(1);
6
配列では、要素の順序を管理するためのメソッドが提供されているため、順序付けされたコレクションを格納するのに適している。
7
let arr = new Array(); let arr = []; 配列はどんな型の要素も格納することができます。 // 値の混在 let arr = [ 'Apple', { name: 'John' }, true, function() { alert('hello'); } ]; // インデックス 1 のオブジェクトを取得し、その名前を表示 alert( arr[1].name ); // John // インデックス 3 の関数を取得し、実行 arr[3](); // hello
8
問題ない 配列は、オブジェクトのようにカンマで終わる場合があります: let fruits = [ "Apple", "Orange", "Plum", ]; すべての行が同じようになるので、“末尾のカンマ” は項目の挿入や削除が容易になります。
9
list.pop() let fruits = ["Apple", "Orange", "Pear"]; alert( fruits.pop() ); // "Pear" を削除し alert する alert( fruits ); // Apple, Orange list.push(...)※複数要素にも対応 let fruits = ["Apple", "Orange"]; fruits.push("Pear"); alert( fruits ); // Apple, Orange, Pear
10
list.shift() let fruits = ["Apple", "Orange", "Pear"]; alert( fruits.shift() ); // Apple を削除し alert する alert( fruits ); // Orange, Pear list.unshift(...)※複数要素にも対応 let fruits = ["Orange", "Pear"]; fruits.unshift('Apple'); alert( fruits ); // Apple, Orange, Pear
11
ベースはオブジェクト なので、任意のプロパティの追加もできる。 ただし非推奨! let fruits = []; // 配列を作ります fruits[99999] = 5; // その length よりも非常に大きなインデックスでプロパティを割り当てます fruits.age = 25; // 任意の名前でプロパティを作成します
12
push/popのほうがよい shift/unshift の場合は、先頭を削除してから、インデックスの再割り当てが必要なので遅い ↑配列が大きいほど遅くなる
13
配列のための for..of という別のループの形式があります: let fruits = ["Apple", "Orange", "Plum"]; // 配列要素の反復処理 for (let fruit of fruits) { alert( fruit ); } ↑値をとりだしてループ処理を行う もちろんオブジェクトでも使える
14
1 for..in は数値のものだけでなく、 全てのプロパティ を繰り返し処理します。 なので、配列に似たオブジェクトなどで、余分なプロパティが混じる可能性あり。 ブラウザや他の環境では 配列のように見える いわゆる “配列のような” オブジェクトがあります。つまり、それらは length とインデックスプロパティを持っています。しかし、それらは通常は必要のない他の非数値プロパティやメソッドも持っています。for..in ループはそれらもリストします。なので、もし配列のようなオブジェクトを処理する必要があるとき、それらの “余分な” プロパティが問題になる場合があります。 2 配列に最適化されてないため遅い for..in ループは配列ではなく、汎用オブジェクトに対して最適化されているため、10から100倍遅くなります。もちろんそれでもとても速いです。高速化はボトルネックの場合にのみ問題なり、それ以外ではさほど重要でないこともあります。しかしそれでも私たちは違いに気をつけるべきです。
15
配列を変更したとき、length プロパティは自動的に更新されます。正確には、それは配列の実際の値の数ではなく、最大の数値インデックスに1を加えたものです。 例えば、大きなインデックスの1つの要素は大きなlengthを返します: let fruits = []; fruits[123] = "Apple"; alert( fruits.length ); // 124 通常、そのように配列を使わないことに注意してください。
16
length プロパティの別の興味深い点は、書き込み可能と言う点です。 手動で増やした場合、面白いことは起きません。しかし、それを減らしたとき、配列は切り捨てられます。この処理は不可逆です。これはその例です: let arr = [1, 2, 3, 4, 5]; arr.length = 2; // 2つの要素に切り捨てる alert( arr ); // [1, 2] arr.length = 5; // length を戻す alert( arr[3] ); // undefined: 値は返ってきません なので、配列をクリアする最もシンプルな方法は arr.length = 0; です
17
配列は、要素のカンマ区切りのリストを返す独自の toString メソッドの実装を持ってます。 let arr = [1, 2, 3]; alert( arr ); // 1,2,3 alert( String(arr) === '1,2,3' ); // true
18
== で比較しないでください オブジェクトと同様の動作、つまり プリミティブへの変換が行われる。 == の引数の一方がオブジェクトで、もう一方がプリミティブの場合、プリミティブに変換されます。 ちなみに厳密比較 === は、型変換をしないためよりシンプルです。 なので、== で配列を比較する場合、全く同じ配列を参照している2つの変数を比較しない限り、決して等価にはなりません。 例: alert( [] == [] ); // false alert( [0] == [0] ); // false プリミティブとの比較では、以下のように、一見すると奇妙な結果がでることがあります: alert( 0 == [] ); // true alert('0' == [] ); // false ここでは、両方のケースで配列オブジェクトとプリミティブを比較しています。なので、配列 [] は比較のためにプリミティブに変換され、空文字 '' になります。 そこから、0と比較する場合は、空文字から0に変換されてtrueとなる。
19
呼び出し arr[2]() は、構文的には古き良き obj[method]() であり、arr が obj の役割を、2 が method の役割を持っています。 従って、arr[2] の関数をオブジェクトメソッドとして呼び出します そのため、答えは以下となる。 // "a","b",function
20
削除する場合、配列のインデックス移動などの操作が必要なので、deleteは使わない。 arr.splice(str) メソッドを利用する。 追加、削除、また要素の挿入もできるメソッドである。※副作用あり 消す位置と消す個数をきめて、あとは入れる要素をわたせる 構文: arr.splice(index, deleteCount, elem1, ..., elemN) 位置 index から始まります。 deleteCount の要素を削除した後、その場所に elem1, ..., elemN を挿入します。このメソッドは削除した要素の配列を返します。 このメソッドは例で簡単に把握できます。 次の例では、3つの要素を削除し、他の2つの要素でそれらを置き換えます: let arr = ["I", "study", "JavaScript", "right", "now"]; // 最初の 3 要素を削除し、別のものに置換 arr.splice(0, 3, "Let's", "dance"); alert( arr ) // 今は ["Let's", "dance", "right", "now"] splice メソッドは削除せずに挿入することも可能です。 負のインデックスも許容します let arr = [1, 2, 5]; // インデックス -1 (末尾から1つ前) から // 削除 0 要素, // その後 3 と 4 を挿入 arr.splice(-1, 0, 3, 4); alert( arr ); // 1,2,3,4,5
21
arr.slice(start, end) 文字列といっしょ let arr = ["t", "e", "s", "t"]; alert( arr.slice(1, 3) ); // e,s (1 から 3 をコピー) alert( arr.slice(-2) ); // s,t (-2 から末尾まで)
22
引数なし arr.slice() でも呼び出すことができ、これは arr のコピーを生成します。 これは、オリジナルの配列に影響を与えない形でさらに変換するためのコピーを取得するのによく使用されます。
23
メソッド arr.concat は配列を他の配列またはアイテムと結合します。 構文: arr.concat(arg1, arg2...) 任意の数の引数(配列または値)を許容します。 結果は arr, 次に arg1, arg2 などのアイテムを含む新しい配列を返します。 ※arr自体は変わらない もし、引数が配列、もしくは Symbol.isConcatSpreadable プロパティを持っている場合、その全ての要素がコピーされます。そうでない場合、引数自体がコピーされます。 let arr = [1, 2]; // arr と [3,4] をマージ alert( arr.concat([3, 4])); // 1,2,3,4 // arr と [3,4] と [5,6] をマージ alert( arr.concat([3, 4], [5, 6])); // 1,2,3,4,5,6 // arr と [3,4] をマージ後, 5 と 6 を追加 alert( arr.concat([3, 4], 5, 6)); // 1,2,3,4,5,6 オブジェクトを追加する場合、要素としてそのまま追加されてしまうが、 オブジェクトに対してSymbol.isConcatSpreadableプロパティを追加することで、配列ライクなオブジェクトとしてふるまうことができ、Concatされた時に、length以外のプロパティを結合対象とすることができる。 let arr = [1, 2]; let arrayLike = { 0: "something", 1: "else", [Symbol.isConcatSpreadable]: true, length: 2 }; alert( arr.concat(arrayLike) ); // 1,2,something,else ↑もし、 [Symbol.isConcatSpreadable]が定義されてなかったら、// 1,2,[object Object]になる。
24
arr.forEach メソッドは配列の全要素に対して関数を実行することができます。 構文: arr.forEach(function(item, index, array) { // ... item に対して何か処理をする }); 例えば、これは配列の各要素を表示します: // 各要素は alert を呼び出す ["Bilbo", "Gandalf", "Nazgul"].forEach(alert); この場合はalert関数は引数itemだけを受け取る ["Bilbo", "Gandalf", "Nazgul"].forEach((item, index, array) => { alert(`${item} is at index ${index} in ${array}`); });
25
メソッド arr.indexOf, arr.lastIndexOf と arr.includes は文字列の場合と同じ構文を持ち、基本的に同じことを行いますが、文字の代わりにアイテムを操作します: arr.indexOf(item, from) はインデックス from から item を探し、見つかった場所のインデックスを返します。そうでない場合は -1 になります。 arr.lastIndexOf(item, from) は同じですが、右から左に見ていきます。 arr.includes(item, from) はインデックス from から item を探し、見つかった場合、true を返します。 let arr = [1, 0, false]; alert( arr.indexOf(0) ); // 1 alert( arr.indexOf(false) ); // 2 alert( arr.indexOf(null) ); // -1 alert( arr.includes(1) ); // true これらのメソッドは厳密な比較、 === 比較を使うことに留意してください! もしも false を探す場合、ゼロではなく、正確な false を見つけようとします。 また、includes の非常に小さな違いは、indexOf/lastIndexOf と違い、NaN を正しく処理することができます: const arr = [NaN]; alert( arr.indexOf(NaN) ); // -1 (0 になるべきですが, === 等値は NaN では機能しません) alert( arr.includes(NaN) );// true (正しい)
26
arr.find メソッド、※arr.findIndex メソッドもある 構文はこうです: let result = arr.find(function(item, index, array) { // true が返却されると、item が返却され、イテレーションは停止します // 偽の場合は undefined です }); 関数は配列の要素毎に繰り返し呼ばれます: item は要素です。 index はインデックスです。 array は配列自身です。 もし true を返すと、検索が止まり、item が返却されます。見つからない場合は undefined になります。 例 let users = [ {id: 1, name: "John"}, {id: 2, name: "Pete"}, {id: 3, name: "Mary"} ]; let user = users.find(item => item.id == 1); alert(user.name); // John arr.findIndex メソッドは基本的に同じです。が、要素自体ではなく要素が見つかったインデックスを返します。
27
検索結果の要素が複数になる可能性がある場合、arr.filter(fn) を使います。 filter はマッチしたすべて要素の配列を返します: let results = arr.filter(function(item, index, array) { // true の場合、item は results にプッシュされ、イテレーションは継続します // 何も見つからない場合は、空配列を返します }); 例: let users = [ {id: 1, name: "John"}, {id: 2, name: "Pete"}, {id: 3, name: "Mary"} ]; // 最初の2人のユーザの配列を返します let someUsers = users.filter(item => item.id < 3); ※アロー関数は1行ならreturnキーワードを省略できる 上の例はBooleanを返している alert(someUsers.length); // 2
28
arr.map メソッド これは、配列の各要素に対して関数を呼び出し、結果の配列を返します。 構文は次の通りです: let result = arr.map(function(item, index, array) { // item の代わりに新しい値を返します }) 例えば、ここでは各要素をその長さに変換します: let lengths = ["Bilbo", "Gandalf", "Nazgul"].map(item => item.length) alert(lengths); // 5,7,6
29
メソッド arr.sort は配列を 決まった位置に ソートし、要素の順番を変更します。 これもソートされた配列を返しますが、arr 自身が変更されるので、返却値は通常無視されます。 ※副作用あり! 関数を渡さない場合は、 文字列に変換されてソートされる。 let arr = [ 1, 2, 15 ]; // このメソッドは arr の内容を並べ替え(てそれを返します) arr.sort(); alert( arr ); // 1, 15, 2←文字列としてソートされた 関数を渡す場合は、 引数二つとる関数を用意する必要がある。 ちなみにa bに入ってくる値は 最適化されたクイックソートアルゴリズムによって選出された二つの要素ということになる。 返却値に関しては、 0より上なら、aをbのあとに並び替える 0より下なら、aをbのまえに並び替える(そのまま) 0なら、そのまま a>b return 1で昇順とおぼえる! なので b aになる! function compareNumeric(a, b) { if (a > b) return 1; if (a == b) return 0; if (a < b) return -1; } let arr = [ 1, 2, 15 ]; arr.sort(compareNumeric); alert(arr); // 1, 2, 15 もっと簡単に記載するとこうなる let arr = [ 1, 2, 15 ]; //aが大きい場合は正の数となり、順番が入れ替わり、bが大きい場合は負の数となりそのまま。 arr.sort( (a, b) => a - b ); alert(arr); // 1, 2, 15
30
str.localeCompare(str2) を利用する これは、 言語規則に従って、str が str2 より大きい場合、1 を返します。 str が str2 より小さい場合は -1 を返します。 それらが等価な場合は 0 を返します。 という関数なのでそのまま利用できる。 let countries = ['Österreich', 'Andorra', 'Vietnam']; alert( countries.sort( (a, b) => a > b ? 1 : -1) ); // Andorra, Vietnam, Österreich (間違い) alert( countries.sort( (a, b) => a.localeCompare(b) ) ); // Andorra,Österreich,Vietnam (正しい!)
31
メソッド arr.reverse は arr 内の要素の順序を逆転させます。 ※副作用あり 例: let arr = [1, 2, 3, 4, 5]; arr.reverse(); alert( arr ); // 5,4,3,2,1 また、反転後に配列 arr を返します。
32
str.split(delim) メソッドは、与えられた区切り文字 delim で文字列を配列に分割します。 let names = 'Bilbo, Gandalf, Nazgul'; let arr = names.split(', '); for (let name of arr) { alert( `A message to ${name}.` ); // A message to Bilbo }
33
split(s) を呼び出すとき、sを空にすると、文字列を文字の配列に分割します: let str = "test"; alert( str.split('') ); // t,e,s,t
34
arr.join(str) は split と逆を行います。arr のアイテムを str で繋いだ文字列を作ります。 例: let arr = ['Bilbo', 'Gandalf', 'Nazgul']; let str = arr.join(';'); alert( str ); // Bilbo;Gandalf;Nazgul
35
メソッド arr.reduce と arr.reduceRight は、配列に基づいて単一の値を計算するために使用されます。 arr.reduceRight メソッドは右側の要素から計算していくだけの違い。 構文: let value = arr.reduce(function(accumulator, item, index, arr) { // ... }, initial); 関数は各要素に順番に適用され、その結果を次の呼び出しに “引き継ぎ” ます: initial は省略可能だが、記載したほうがよいとされている 引数: accumulator – 前の関数呼び出しの結果で、初回は initial と等価です(initial が指定されている場合) item – 現在の配列の項目です。 index – 位置です。 arr – 配列です。 関数が適用されると、前の関数呼び出しの結果が、次の関数呼び出しの最初の引数として渡されます。 let arr = [1, 2, 3, 4, 5]; let result = arr.reduce((sum, current) => sum + current, 0); ↑0はinitial、つまり初期値のこと alert(result); // 15 0+1 1+2 3+3 6+4 10+5 てかんじで足し合わされてった感じ。
36
初期値が指定されていない場合、reduce は配列の最初の要素を初期値とみなし、2つ目の要素から繰り返し処理を始める。 そのため空配列を初期値なしで処理しようとすると、エラーとなるらしい 従って、常に初期値を指定することをおすすめします
37
配列は別の言語の型を形成していないため Objectとなる!
38
メソッド Array.isArray(value) があります。これは、value が配列のときに true を、そうでない場合には false を返します。 alert(Array.isArray({})); // false alert(Array.isArray([])); // true
39
まず、sortはサポートしてなくて、 find、filter、mapとかでサポートしているらしい。 配列メソッドは渡された関数を実行するが、その際メソッド実行ではなく関数実行となってしまうので、内部のthisの値がグローバルオブジェクトを指してしまう。 これを回避するため、thisArgパラメータでthisの値を明示的にバインドする。 let army = { minAge: 18, maxAge: 27, //booleanを返すメソッド canJoin(user) { return user.age >= this.minAge && user.age < this.maxAge; } }; let users = [ {age: 16}, {age: 20}, {age: 23}, {age: 30} ]; // army.canJoin関数に各userが渡されて関数実行される。 let soldiers = users.filter(army.canJoin, army); alert(soldiers.length); // 2 alert(soldiers[0].age); // 20 alert(soldiers[1].age); // 23 もし上の例で users.filter(army.canJoin) としていた場合、army.canJoin はスタンドアローンの関数として呼び出されるため、this=undefined であり、即時エラーになります。
40
関数を直接渡すのではなく、緩衝材として関数を作り、そこでメソッド実行してやるとよい。 呼び出し users.filter(army.canJoin, army) は users.filter(user => army.canJoin(user)) に置き換え可能である。 多くの人にとってより理解しやすいので、後者の方がよく利用されます。
41
arr.some(fn)/arr.every(fn) は配列の各要素に対してチェックを行い、真偽値を返す。 引数の関数には各要素のvalueとindexが引数としてとることができる。 valueの値をチェックして真偽値を返す関数を定義する。 someは|| every は&&として使える。 もし fn が真の値を返す場合、arr.some() はすぐに true を返し、残りの項目に対するイテレーションを停止します。 偽なら次のイテレーションへ。 fn が偽の値を返す場合は、arr.every() はすぐに false を返し、同様に残りの項目のイテレーションは停止します。 every は配列を比較するのに使えます: function arraysEqual(arr1, arr2) { // 配列の長さが同じであること、 arr1の値が、arr2の同じインデックスの値と全ての要素で同じなら trueを返す。 一個でも違えばfalseを返す。 return arr1.length === arr2.length && arr1.every((value, index) => value === arr2[index]); } alert( arraysEqual([1, 2], [1, 2])); // true
42
良い問題なのでやれ コツはプロパティの配列でメソッドを管理している。 この配列にはメソッドを追加できるので、拡張可能としている。 キャルクレートメソッドを起動することで、引数に合わせたメソッドを配列から起動する感じ
43
問題あり、上記の問題はreturnを省略しており、さらに、オブジェクトリテラルのカッコは処理部分の省略されたカッコであると解釈されてしまう。 なので、結果はこうなる。 const res = [1,2,3].map(i => {res: i}) console.log(res) [ undefined, undefined, undefined ] 対策する場合は、returnを利用する const res = [1,2,3].map(i => { return { res: i } }) console.log(res) [ {res: 1}, {res: 2}, {res: 3} ] それか、丸括弧でオブジェクトリテラルをかこむ const res = [1,2,3].map(i => ({res: i})) console.log(res) [ {res: 1}, {res: 2}, {res: 3} ]
44
for..of ループが使用できるオブジェクトのこと
45
range を 反復可能(iterable) にするために (for..of を動作させるために)は、Symbol.iterator というメソッドをオブジェクトに追加する必要がある。 以下の特性がある。 for..of が始まると、そのメソッドを呼び出します(なければエラーになります)。 メソッドは iterator (メソッド next をもつオブジェクト)を返さなければいけません。 for..of が次の値を必要とするとき、そのオブジェクトの next() を呼びます。 next() の結果は {done: Boolean, value: any} の形式でなければなりません。 そして done=true は繰り返しが終わったことを示します。 そうでない場合は、value は新しい値である必要があります。 これは range の完全な実装です: let range = { from: 1, to: 5 }; // 1. for..of の呼び出しは、最初にこれを呼び出します range[Symbol.iterator] = function() { // ...これは iterator オブジェクトを返します: // 2. 以降、for..of はこのイテレータでのみ機能し、次の値を要求します return { current: this.from, last: this.to, // 3. for..of ループにより、各繰り返しで next() が呼ばれます next() { // 4. オブジェクト {done:.., value :...} を返す必要があります if (this.current <= this.last) { return { done: false, value: this.current++ }; } else { return { done: true }; } } }; }; // これで動作します! for (let num of range) { alert(num); // 1, 2, 3, 4, 5 } 反復可能(iterables)の中心的な機能に注目してください。関心の分離です。 range 自身は next() メソッドを持っていません。 代わりに、別のオブジェクト、いわゆる “イテレータ” は range[Symbol.iterator]() の呼び出しで生成され、反復を処理します。 従って、反復オブジェクトは反復処理されるオブジェクトから分離されています。
46
rangeオブジェクトにnext()を実装する。 同時に[Symbol.iterator]メソッドを定義し、自身を返す。 let range = { from: 1, to: 5, [Symbol.iterator]() { this.current = this.from; // 自身を返す。 return this; }, next() { if (this.current <= this.to) { return { done: false, value: this.current++ }; } else { return { done: true }; } } }; for (let num of range) { alert(num); // 1, そして 2, 3, 4, 5 }
47
欠点は、オブジェクトに対して同時に2つの for..of ループを実行することは不可能だということです。 イテレータ が1つしかないので、オブジェクトは繰り返し状態を共有します。 ですが、2つの並列 for-of はたとえ非同期のシナリオにおいてもまれです。
48
先ほどの例では、range.to = Infinity にすることで、range が無限大になります。 next でdone:trueにせず、valueの値を常に生成しつづけることも可能。 それで、擬似乱数の無限のシーケンスを生成する反復可能なオブジェクトを作ることができます。 もちろん、このような反復可能なオブジェクトに対する for..of ループはエンドレスですが、break を使っていつでも止めることができます。
49
文字列 for (let char of "test") { // 文字ごとに1回、計4回実行します。 alert( char ); // t, 次に e, 次に s, そして t } そしてサロゲートペアも正しく動作します! let str = '𝒳😂'; for (let char of str) { alert( char ); // 𝒳, そして次は 😂 }
50
let str = "Hello"; // for (let char of str) alert(char); // と同じことをしています //イテレータを取得 let iterator = str[Symbol.iterator](); while (true) { // nextメソッドを呼び出し let result = iterator.next(); // doneがtrueならループを抜ける if (result.done) break; alert(result.value); // 1つずつ文字を出力します }
51
反復可能(Iterables) は上で説明したように、Symbol.iterator メソッドを実装したオブジェクトです。 配列ライク(Array-likes) は、インデックスと length を持ったオブジェクトです。なので、これらは配列のように見えます。 例えば、文字列は 反復可能(iterable) (for..of が動作する) であり、かつ 配列ライク(array-like) (数値インデックスと length を持っています) です。
52
Array.from メソッドがあります。 これは 反復可能(iterable) または 配列ライク(array-like) な値を引数に取り、そこから “本当の” Array を作ります。 それ以降、配列のメソッドを呼べるようになります。 let arrayLike = { 0: "Hello", 1: "World", length: 2 }; let arr = Array.from(arrayLike); // (*) alert(arr.pop()); // World (メソッドが動作します) 行 (*) の Array.from はオブジェクトを取り出し、反復可能(iterable) か 配列ライク(array-like) なのか調べ、新しい配列を作りすべてのアイテムをコピーします。
53
2つ目の引数 mapFn を利用する。 Array.from の完全な構文では、オプションで “マッピング” 関数を指定できます: Array.from(obj[, mapFn, thisArg]) ↑[]の間は任意って意味 2つ目の引数 mapFn は、配列に追加する前に各要素に適用する関数であり、thisArg はそこでの this を指定できます。 // range は前問の例で利用したものと仮定 // 各数値の平方 let arr = Array.from(range, num => num * num); alert(arr); // 1,4,9,16,25 まーMap関数があるしあんまおぼえなくていいかも
54
文字列を文字配列に変換するために Array.from を使います: let str = '𝒳😂'; // str を文字の配列に分割します let chars = Array.from(str); alert(chars[0]); // 𝒳 alert(chars[1]); // 😂 alert(chars.length); // 2 str.split とは違い、文字の反復可能な性質に依存するため、for..of のようにサロゲートペアでも正しく動作します。 技術的には、これは以下と同じことをしています: let str = '𝒳😂'; let chars = []; // Array.from は内部では同じループをします for (let char of str) { chars.push(char); } alert(chars); …が、より短く書けます。 これを活用することで、 サロゲートを意識した slice を実装することもできます!
55
Map は Object と同じように、キー付されたデータ項目の集まりです。主な違いは Map は任意の型のキーを許可することです。 もちろんオブジェクトもキーにできる。 オブジェクトとは違い、キーは文字列には変換されません。任意の型のキーが利用可能です。 let map = new Map(); map.set('1', 'str1'); // 文字列キー map.set(1, 'num1'); // 数値キー map.set(true, 'bool1'); // 真偽値キー // 通常のオブジェクトを覚えていますか?キーを文字列に変換していました。 // Map は型を維持します。なので、これらは別ものです: alert( map.get(1) ); // 'num1' alert( map.get('1') ); // 'str1' alert( map.size ); // 3 繰り返しは値が挿入された順で行われます。通常の Object とは違い、Map はこの順番を保持しています
56
map.set(key, value) – キーで、値を格納します. map 自身を返すので、呼び出しを “チェーン” することができます: map.set('1', 'str1') .set(1, 'num1') .set(true, 'bool1'); map.get(key) – 指定されたキーの値を返却します。map に存在しない key の場合には undefined になります. map.has(key) – キーが存在する場合に true を返します。そうでなければ false になります. map.delete(key) – キーで値を削除します. map.clear() – map をクリアします. map.size – 現在の要素の数です.
57
できるけど非推奨 キーが 文字列とシンボルキーでしか使えない これは map を通常の JavaScript オブジェクトとして扱っているので、対応するすべての制限(文字列/シンボルキーのみなど)があることを意味します。
58
オブジェクトで、キーにオブジェクトは使えない。 なので、そのオブジェクトは自動で文字列に変換される。 つまり、 "[object Object]"がキーとなる。
59
等価のテストをするために、Map は SameValueZero アルゴリズムを使います。大雑把には厳密等価 === と同じですが、違いは NaN は NaN と等しいとみなされる点です。なので、NaN も同様にキーとして使うことができます。
60
map.keys() – キーに対する iterable を返します。 map.values() – 値に対する iterable を返します。 map.entries() – エントリ [key, value](配列) の iterable を返します。これは for..of でMapオブジェクトを指定すると暗黙的に使われます。 let recipeMap = new Map([ ['cucumber', 500], ['tomatoes', 350], ['onion', 50] ]); // キー(野菜)の反復 for (let vegetable of recipeMap.keys()) { alert(vegetable); // cucumber, tomateos, onion } // 値(量)の反復 for (let amount of recipeMap.values()) { alert(amount); // 500, 350, 50 } // [key, value] エントリーの反復 for (let entry of recipeMap) { // recipeMap.entries() と同じ alert(entry); // cucumber,500 (など) } ※ちなみに。。 Map は Array と同じように、組み込みの forEach メソッドを持っています。 // 各 (key, value) ペアに対して関数を実行 recipeMap.forEach( (value, key, map) => { alert(`${key}: ${value}`); // cucumber: 500 etc });
61
new Mapで、 キー/値のペア(配列)をもつ、配列またはイテラブルを渡すと生成できる。 // [key, value] ペアの配列 let map = new Map([ ['1', 'str1'], [1, 'num1'], [true, 'bool1'] ]); alert( map.get('1') ); // str1
62
オブジェクトのキー/値のペアの配列を、その形式で返す組み込みのメソッド Object.entries(obj) を使用できます。 なので、次のようにオブジェクトから map の初期化をすることができます: let obj = { name: "John", age: 30 }; let map = new Map(Object.entries(obj)); alert( map.get('name') ); // John ここで、Object.entries はキー/値のペアの配列を返します: [ ["name","John"], ["age", 30] ]。これは Map が必要とするものです。
63
Map から通常のオブジェクトを取得する際に Object.fromEntries が使えます。 これは、キー/値ペアの配列からオブジェクトを生成する。 map.entries()は、マップからキー/値ペアの配列を返すので、これをObject.fromEntriesで読み込むと、オブジェクトになる。 例 let map = new Map(); map.set('banana', 1); map.set('orange', 2); map.set('meat', 4); let obj = Object.fromEntries(map.entries()); // マップからキー/値ペアの配列を生成し、通常のオブジェクトを作成します (*) // 完了! // obj = { banana: 1, orange: 2, meat: 4 } alert(obj.orange); // 2 また、行 (*) をより短くすることもできます: let obj = Object.fromEntries(map); これでもいい。 なぜなら、Object.fromEntries は引数に反復可能なオブジェクトを期待するからです。つまり配列である必要はありません。 そして、map の標準のイテレーションは map.entries() と同じキー/値を返します。 したがって、map と同じキー/値を持つプレーンなオブジェクトが取得できます。
64
Set は、特別タイプのコレクションで、 キーなしで、値のみ。 値は一意という特徴がある Set のイテレーションは常に挿入順で行われます let set = new Set(); let john = { name: "John" }; let pete = { name: "Pete" }; let mary = { name: "Mary" }; // 訪問、何度も来るユーザもいます set.add(john); set.add(pete); set.add(mary); set.add(john); set.add(mary); // set はユニークな値のみをキープします alert( set.size ); // 3 for (let user of set) { alert(user.name); // John (そして Pete と Mary) }
65
new Set(iterable) – set を作ります。オプションで値の配列(任意の iterable が指定可能)からも可能です。 set.add(value) – 値を追加し、 set 自身を返します。 set.delete(value) – 値を削除し、value が呼び出し時に存在すれば true, そうでなければ false を返します。 set.has(value) – set の中に値が存在すれば true を返し、それ以外は false です。 set.clear() – set から全てを削除します。 set.size – set の要素数です。
66
Mapとの互換性が意識されている。 主なメソッドは以下の通り set.keys() – 値に対する iterable なオブジェクトを返します。※キーではないので注意 set.values() – set.keys と処理内容は同じ、Map との互換性のために作られたもの。 set.entries() – [value, value] のエントリのための iterable なオブジェクトを返します。Map の互換性のために存在します。 Set の中の forEach 関数もMapとの互換性が意識されており、 3つの引数を持っています: 値(value), 次に 再び値(valueAgain), 次にターゲットのオブジェクトです。実際、引数には同じ値が2回出現します。 let set = new Set(["oranges", "apples", "bananas"]); for (let value of set) alert(value); // forEach と同じ: set.forEach((value, valueAgain, set) => { alert(value); });
67
オブジェクトをキーとして管理し、 キーは到達可能性を保有しないことが特徴。 WeakMap のキーはプリミティブな値ではなくオブジェクト限定。 オブジェクトをキーとして使用し、そのオブジェクトへの参照がWeakMap以外になかくなった場合、自動的にメモリ(と map)から削除されます。 let john = { name: "John" }; let weakMap = new WeakMap(); weakMap.set(john, "..."); john = null; // 参照を上書きします // john はメモリから削除されます! 通常のMapであれば、johnにnullが代入されたとしても、 Mapのキーでjohn を参照していので到達可能であり、ガベージコレクションの対象とはならないが WeakMapで扱うキーについては、 到達可能性を保有したことにならない! そのため、ガベージコレクションの対象となる
68
WeakMap は繰り返しと、メソッド keys(), values(), entries() をサポートしません。 そのため、すべてのキーや値を取得する方法はありません。 ガベージコレクションによるクリーンアップのタイミングがわからないので、到達可能性がなくても、まだエンティティか残ってる場合がある。 なので、エンティティが生きてるか消えてるか不定なのでサポートしてない。
69
WeakMap は次のメソッドのみを持っています: weakMap.get(key) weakMap.set(key, value) weakMap.delete(key, value) weakMap.has(key)
70
ライブラリ側で、メイン側から渡されるオブジェクトを保持する場合、 WeakMapで保持しておくと、 メイン側で参照をなくした時に、ガベージコレクションの対象とさせることができる。 ライブラリ側 📁 visitsCount.js let visitsCountMap = new WeakMap(); // weakmap: user => visits count // 訪問数を増加 function countUser(user) { let count = visitsCountMap.get(user) || 0; //メイン側で渡されるオブジェクトをWeakMapで管理! visitsCountMap.set(user, count + 1); } メイン側 // 📁 main.js let john = { name: "John" }; countUser(john); // 訪問をカウント // 参照をなくす!=ガベージコレクションの対象となる。 john = null;
71
キャッシュ機能など履歴や実績の管理を実装することができる。 関数からの結果を保持(“キャッシュ”)できるので、同じオブジェクトに対する将来の呼び出しで再利用することができます。 この時WeakMapを利用することによって、キャッシュした値のクリーンアップができるようになる。 // 📁 cache.js let cache = new WeakMap(); // 計算し結果を覚える function process(obj) { //計算済みかどうか判断 if (!cache.has(obj)) { let result = obj /* に対する計算結果 */; cache.set(obj, result); } //計算済みであれば、その時の計算結果を返す return cache.get(obj); } // 📁 main.js let obj = {/* some object */}; let result1 = process(obj); // キャッシュから取得した、記憶された結果が使われます let result2 = process(obj); // ...後ほど、オブジェクトがこれ以上は不要になったとき obj = null; // WeakMap なので cache.size は取得できません // が、0 あるいはすぐに 0 になります // オブジェクトがガベージコレクトされると、キャッシュされたデータも同様に削除されます。
72
WeakMapのSet版 Set とちがい、WeakSet へはオブジェクトのみ追加できる。 WeakMapと同様に到達可能性を保持しない WeakMap と同様 WeakSet も、イテレーションの欠如と現在のすべてのコンテンツを取得することができない。 例えば、ユーザを WeakSet に追加して、サイトにアクセスしたユーザを追跡できます。: let visitedSet = new WeakSet(); let john = { name: "John" }; let pete = { name: "Pete" }; let mary = { name: "Mary" }; visitedSet.add(john); // John が訪問 visitedSet.add(pete); // 次に Pete visitedSet.add(john); // John 再び // visitedSet は 2 ユーザいます // John が訪問したかどうかをチェック alert(visitedSet.has(john)); // true // Mary が訪問したかをチェック alert(visitedSet.has(mary)); // false john = null;
73
Mapと同様のものが用意されている。 しかし、メソッドではなく関数であることが異なる。 Object.keys(obj) – キーの配列を返します。 Object.values(obj) – 値の配列を返します。 Object.entries(obj) – [key, value] ペアの配列を返します。 map.keys()のように、obj.keys()ではないことに注意! 関数 Object.keys(obj)形式である。 また、それぞれの戻り値もiterable ではなく、“本当の” Arrayであることに注意
74
主な理由は柔軟性です。JavaScript ではオブジェクトはすべての複雑な構造のベースであることを忘れないでください。 そのため、独自の order.values() メソッドを実装する order という独自のオブジェクトがあるかもしれません。 それでも Object.values(order) を呼ぶことができます。 ちなみに、 Object.* メソッドが単なる iterable ではなく “本当の” 配列オブジェクトを返すことに関しては、主に歴史的な理由らしい
75
それらを適用したい場合は、Object.fromEntries に続いて、Object.entries が使用できます。: Object.entries(obj) を使用して obj からキー/値ペアの配列を取得します。 その配列で、配列のメソッドを使用します。例えば map 結果の配列で Object.fromEntries(array) を使用して、配列をオブジェクトに戻します。 let prices = { banana: 1, orange: 2, meat: 4, }; let doublePrices = Object.fromEntries( // 配列に変換して map を実行、その後 fromEntries でオブジェクトに戻します Object.entries(prices).map(([key, value]) => [key, value * 2]) ); alert(doublePrices.meat); // 8
76
// 姓名の配列があります let arr = ["John", "Smith"] // 変数へ分割して代入 // 普通のパターン let firstName = arr[0]; let surname = arr[1]; // 上を短く書いたパターン これを分割代入という! let [firstName, surname] = arr; alert(firstName); // John alert(surname); // Smith
77
配列の不要な要素は、余分なカンマをつけることで捨てることができます: // 1番目、2番目の要素が不要の場合 let [, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic"]; alert( title ); // Consul 上のコードでは、最初の2つの要素がスキップされ、3つ目は title に代入され、残りもスキップされています。
78
右辺は任意の反復可能(iterable)に対して動作します …実際には配列だけでなく、任意の反復可能(iterable)に対して使うことができます: let [a, b, c] = "abc"; // ["a", "b", "c"] let [one, two, three] = new Set([1, 2, 3]); 内部的には分割代入は右辺の値に対してイテレーションすることで動作するため、これも動作します。 これは = の右側の値に対して for..of を呼び出し、値を代入するためのシンタックスシュガーの一種です。
79
オブジェクトの key-value をループするのに、分割代入を一緒に使うこともできます: let user = { name: "John", age: 30 }; // key-value のループ for (let [key, value] of Object.entries(user)) { alert(`${key}:${value}`); // name:John, then age:30 }
80
let guest = "Jane"; let admin = "Pete"; // 値を入れかえましょう: guest=Pete, admin=Jane ちなみに右辺は配列を形成してるだけ [guest, admin] = [admin, guest]; alert(`${guest} ${admin}`); // Pete Jane (successfully swapped!) ここでは、2つの変数の一時的な配列を作り、その直後、入れ替えた順番で分割しました。 この方法で2つ以上の変数を入れ替えることも可能です。
81
省略されます。 続く項目もすべて取得したい場合は、3つのドット "..." を使用して “残り” を取得するパラメータを1つ追加します。: 配列で取得される let [name1, name2, ...rest] = ["Julius", "Caesar", "Consul", "of the Roman Republic"]; // rest は3つ目の項目からの配列です alert(rest[0]); // Consul alert(rest[1]); // of the Roman Republic alert(rest.length); // 2 restの値は、残りの配列要素の配列です。 rest の代わりに他の変数名を使用できます。その前に3つのドットがあり、分割代入の最後にくるようにしてください。
82
値が足りない場合は、代入されないので、undefinedとなる。 値がなかった場合に “デフォルト” 値を使いたければ、= を使ってデフォルト値を指定することができます: デフォルト値はより複雑な式や関数呼び出しにすることもできます。それらは値が提供されなかったときのみ評価されます。 例えば、ここでは2つのデフォルトに対して prompt 関数を使っていますが、値がなかった場合のみ実行されます: // 姓のプロンプトのみを実行する let [name = prompt('name?'), surname = prompt('surname?')] = ["Julius"]; alert(name); // Julius (配列から) alert(surname); // プロンプトが得たもの ↑デフォルト値をの評価は値がなかったときのみ!、
83
let {var1, var2} = {var1:…, var2…} 右辺には、変数に分割したい既存のオブジェクトがあります。 左辺には該当するプロパティの “パターン” を指定します。 単純なケースでは、それは {...} に変数名を並べたものです。 例: let options = { title: "Menu", width: 100, height: 200 }; let {title, width, height} = options; alert(title); // Menu alert(width); // 100 alert(height); // 200 プロパティ options.title, options.width と options.height は、該当する変数に代入されます。
84
順番は関係ありません。これも動作します。: // let {...} 内のプロパティ順を変えた場合 let {height, width, title} = { title: "Menu", height: 200, width: 100 } 同名の変数名でマッピングされている!
85
コロンを使うことでセットすることができます: let options = { title: "Menu", width: 100, height: 200 }; // { 元のプロパティ: ターゲットとなる変数 } let {width: w, height: h, title} = options; // width -> w // height -> h // title -> title alert(title); // Menu alert(w); // 100 alert(h); // 200 コロンは “何を: どこに” を示します。
86
コロンと等号の両方を組み合わせることもできます。: let options = { title: "Menu" }; let {width: w = 100, height: h = 200, title} = options; alert(title); // Menu alert(w); // 100 alert(h); // 200
87
配列といっしょ let options = { title: "Menu", height: 200, width: 100 }; // title = title と名前付けられたプロパティ // rest = オブジェクトのプロパティの残り let {title, ...rest} = options; // now title="Menu", rest={height: 200, width: 100} alert(rest.height); // 200 alert(rest.width); // 100
88
オブジェクトリテラルとして右辺を書いているつもりだが、 JavaScriptによってコードブロックと認識されてしまいエラーとなってしまう。 コードブロックとは、以下のような 文をグループ化するために使われます。 { // a code block let message = "Hello"; // ... alert( message ); } コードブロックではないと JavaScript に示すためには、代入全体を括弧 (...) で囲む必要があります: let title, width, height; // これでOKです ({title, width, height} = {title: "Menu", width: 200, height: 100}); alert( title ); // Menu
89
左辺は右辺のパターンにあわせて、 配列なら[] オブジェクトなら{} を利用して分割代入していくことができる。 let options = { size: { width: 100, height: 200 }, items: ["Cake", "Donut"], extra: true }; // わかりやすくするために、複数の行での分割代入 let { size: { // ここにサイズを格納 width, height }, items: [item1, item2], // ここに items を割り当てる title = "Menu" // オブジェクトには存在しない (デフォルト値が使われます) } = options; alert(title); // Menu alert(width); // 100 alert(height); // 200 alert(item1); // Cake alert(item2); // Donut 左辺で言及されていなかった extra を除いた options オブジェクト全体が該当する変数に代入されます。 最終的には、width, height, item1, item2 と、デフォルト値から title を得ます。 代わりに中身を取得しているので、size と items の変数はないことに注意してください。
90
非構造化
91
ある関数が多くのパラメータを持っており、ほどんどがオプションであることがあります。特にユーザインタフェースのときに当てはまります。メニューを作る関数を想像してみてください。幅と高さ、タイトル、アイテムのリストなどを持っています。 ここに、良くない関数の書き方があります: function showMenu(title = "Untitled", width = 200, height = 100, items = []) { // ... } 現実の問題の1つは、どうやって引数の順番を覚えるか、です。コードがしっかりドキュメント化されていれば、通常は IDE が助けてくれます。しかし、他にも問題があります。ほとんどのパラメータがデフォルトでOKの場合の関数の呼び方です。 こうなりますか? // デフォルト値で良い場合は undefined にする showMenu("My Menu", undefined, undefined, ["Item1", "Item2"]) 非常に扱いづらい。。 このようなケースで非構造化を利用する! オブエジェクトとしてパラメータを渡し、関数はそれらを変数に分解します: let options = { title: "My menu", items: ["Item1", "Item2"] }; function showMenu({ title = "Untitled", width: w = 100, // width は w に height: h = 200, // height は h に items: [item1, item2] // items の最初の要素は item1 へ、次は item2 へ }) { alert( `${title} ${w} ${h}` ); // My Menu 100 200 alert( item1 ); // Item1 alert( item2 ); // Item2 } showMenu(options);
92
分割代入は右辺になにもないとエラーとなる。 分割代入は showMenu() に引数があることを前提にしている点に注意してください。もしすべての値をデフォルトにしたい場合には、空のオブジェクトを指定する必要があります: showMenu({}); // OK, すべての値はデフォルト値になります showMenu(); // これはエラーになります
93
非構造化対象全体のデフォルト値に {} を指定することで対応することができます: function showMenu({ title = "Menu", width = 100, height = 200 } = {}) { alert( `${title} ${width} ${height}` ); } showMenu(); // Menu 100 200 上のコードでは、全体の引数オブジェクトがデフォルトで {} なので常に分解する何かがあります。
94
new Date() 引数なし – 現在の日付と時刻で Date オブジェクトを作ります: new Date(milliseconds) Jan 1st of 1970 UTC+0 (1970年 1月1日 UTC+0) からの経過したミリ秒(秒の1/1000)に等しい時間をもつ Date オブジェクトを作ります。 new Date(datestring) 1つの引数でそれが文字列の場合、自動でパースされます。Date.parse アルゴリズム(後述)でパースされます。 new Date(year, month, date, hours, minutes, seconds, ms) ローカルタイムゾーンで、与えられた要素で日付を作成します。最初の2つの引数は必須です。
95
タイムスタンプ
96
ローカルタイムゾーンで取得する タイムゾーン UTC+0 の日、月、年などを返す、UTCカウンターパートもあります:getUTCFullYear(), getUTCMonth(), getUTCDay().
97
getTime() 日付のタイムスタンプを返します – それは、1970年 UTC+0 の 1月1日からの経過ミリ秒です。 getTimezoneOffset() ローカルタイムゾーンとUTCの差を、分で返します: // タイムゾーン UTC-1 にいる場合、60 を出力 // タイムゾーン UTC+3 にいる場合、-180 を出力 alert( new Date().getTimezoneOffset() );
98
自動補正 は Date オブジェクトのとても便利な機能です。私たちが範囲外の値を指定した場合、それは自動的に調節されます。 2013/2/1が出力される。 はみ出した分は自動補正によって、計算される。 つまり、32日が自動補正によってくりあがり、次の月の次の日に補正された。 また、ゼロや負値をセットすることもできます。例えば: let date = new Date(2016, 0, 2); // 2 Jan 2016 date.setDate(1); // 月の1日を設定します alert( date ); date.setDate(0); // 0日はない。最小日は1なので、先月の最後の日になります alert( date ); // 31 Dec 2015
99
Date オブジェクトが数値へ変換されるとき、date.getTime() と同じようにタイムスタンプになります: let date = new Date(); alert(+date); // ミリ秒の数値です, date.getTime() と同じです
100
現在のタイムスタンプを返す特別なメソッド Date.now() があります。 これは、意味的には new Date().getTime() と同じですが、中間の Date オブジェクトを作らないため、より速く、ガベージコレクションに負荷をかけません。 これはおそらくベターです: let start = Date.now(); // 1 Jan 1970 からのミリ秒 // なにかする for (let i = 0; i < 100000; i++) { let doSomething = i * i * i; } let end = Date.now(); // 終了 alert( `The loop took ${end - start} ms` ); // 日付ではなく、数値を減算する
その他
その他
谷峻輔 · 12問 · 2年前その他
その他
12問 • 2年前LWC
LWC
谷峻輔 · 100問 · 2年前LWC
LWC
100問 • 2年前LWC2
LWC2
谷峻輔 · 28問 · 2年前LWC2
LWC2
28問 • 2年前Javascript
Javascript
谷峻輔 · 100問 · 2年前Javascript
Javascript
100問 • 2年前javascript2
javascript2
谷峻輔 · 58問 · 2年前javascript2
javascript2
58問 • 2年前js1 JavaScript の基礎
js1 JavaScript の基礎
谷峻輔 · 92問 · 2年前js1 JavaScript の基礎
js1 JavaScript の基礎
92問 • 2年前js2 コード品質、オブジェクト基本、データ型
js2 コード品質、オブジェクト基本、データ型
谷峻輔 · 100問 · 2年前js2 コード品質、オブジェクト基本、データ型
js2 コード品質、オブジェクト基本、データ型
100問 • 2年前js4 データ型、関数の高度な機能
js4 データ型、関数の高度な機能
谷峻輔 · 100問 · 2年前js4 データ型、関数の高度な機能
js4 データ型、関数の高度な機能
100問 • 2年前js5 関数の高度な機能 オブジェクトプロパティの設定 プロトタイプ, 継承プロトタイプ, 継承、クラス
js5 関数の高度な機能 オブジェクトプロパティの設定 プロトタイプ, 継承プロトタイプ, 継承、クラス
谷峻輔 · 96問 · 2年前js5 関数の高度な機能 オブジェクトプロパティの設定 プロトタイプ, 継承プロトタイプ, 継承、クラス
js5 関数の高度な機能 オブジェクトプロパティの設定 プロトタイプ, 継承プロトタイプ, 継承、クラス
96問 • 2年前js6 クラス Promise, async/await
js6 クラス Promise, async/await
谷峻輔 · 100問 · 2年前js6 クラス Promise, async/await
js6 クラス Promise, async/await
100問 • 2年前js7 Promise, async/await、ジェネレータ, 高度なイテレーション、モジュール
js7 Promise, async/await、ジェネレータ, 高度なイテレーション、モジュール
谷峻輔 · 96問 · 2年前js7 Promise, async/await、ジェネレータ, 高度なイテレーション、モジュール
js7 Promise, async/await、ジェネレータ, 高度なイテレーション、モジュール
96問 • 2年前js8 その他
js8 その他
谷峻輔 · 57問 · 2年前js8 その他
js8 その他
57問 • 2年前Javaとは〜
Javaとは〜
谷峻輔 · 83問 · 2年前Javaとは〜
Javaとは〜
83問 • 2年前Reactクイックスタート
Reactクイックスタート
谷峻輔 · 15問 · 2年前Reactクイックスタート
Reactクイックスタート
15問 • 2年前デザインパターン
デザインパターン
谷峻輔 · 5問 · 2年前デザインパターン
デザインパターン
5問 • 2年前承認申請
承認申請
谷峻輔 · 16問 · 2年前承認申請
承認申請
16問 • 2年前アプリケーションビルダー2
アプリケーションビルダー2
谷峻輔 · 100問 · 2年前アプリケーションビルダー2
アプリケーションビルダー2
100問 • 2年前アプリケーションビルダー3
アプリケーションビルダー3
谷峻輔 · 100問 · 2年前アプリケーションビルダー3
アプリケーションビルダー3
100問 • 2年前アプリケーションビルダー4
アプリケーションビルダー4
谷峻輔 · 100問 · 2年前アプリケーションビルダー4
アプリケーションビルダー4
100問 • 2年前アプリケーションビルダー5
アプリケーションビルダー5
谷峻輔 · 94問 · 2年前アプリケーションビルダー5
アプリケーションビルダー5
94問 • 2年前アプリケーションビルダー6
アプリケーションビルダー6
谷峻輔 · 100問 · 2年前アプリケーションビルダー6
アプリケーションビルダー6
100問 • 2年前アプリケーションビルダー7
アプリケーションビルダー7
谷峻輔 · 100問 · 2年前アプリケーションビルダー7
アプリケーションビルダー7
100問 • 2年前アプリケーションビルダー8
アプリケーションビルダー8
谷峻輔 · 98問 · 2年前アプリケーションビルダー8
アプリケーションビルダー8
98問 • 2年前アプリケーションビルダー9
アプリケーションビルダー9
谷峻輔 · 70問 · 2年前アプリケーションビルダー9
アプリケーションビルダー9
70問 • 2年前フロー
フロー
谷峻輔 · 42問 · 2年前フロー
フロー
42問 • 2年前レポート、ダッシュボード
レポート、ダッシュボード
谷峻輔 · 60問 · 2年前レポート、ダッシュボード
レポート、ダッシュボード
60問 • 2年前SalesCloud
SalesCloud
谷峻輔 · 18問 · 2年前SalesCloud
SalesCloud
18問 • 2年前標準機能
標準機能
谷峻輔 · 72問 · 2年前標準機能
標準機能
72問 • 2年前宣言的開発
宣言的開発
谷峻輔 · 8問 · 2年前宣言的開発
宣言的開発
8問 • 2年前数式、人力規則
数式、人力規則
谷峻輔 · 18問 · 2年前数式、人力規則
数式、人力規則
18問 • 2年前アクセスレベル
アクセスレベル
谷峻輔 · 63問 · 2年前アクセスレベル
アクセスレベル
63問 • 2年前データ型変換
データ型変換
谷峻輔 · 22問 · 2年前データ型変換
データ型変換
22問 • 2年前オブジェクト、項目
オブジェクト、項目
谷峻輔 · 91問 · 2年前オブジェクト、項目
オブジェクト、項目
91問 • 2年前アプリ、タブ
アプリ、タブ
谷峻輔 · 92問 · 2年前アプリ、タブ
アプリ、タブ
92問 • 2年前自動化
自動化
谷峻輔 · 17問 · 2年前自動化
自動化
17問 • 2年前組織、開発モデル
組織、開発モデル
谷峻輔 · 65問 · 2年前組織、開発モデル
組織、開発モデル
65問 • 2年前ボタン、アクション
ボタン、アクション
谷峻輔 · 69問 · 2年前ボタン、アクション
ボタン、アクション
69問 • 2年前インテグレーション
インテグレーション
谷峻輔 · 40問 · 2年前インテグレーション
インテグレーション
40問 • 2年前ページレイアウト、リストビュー、レコードタイプ、プロセス
ページレイアウト、リストビュー、レコードタイプ、プロセス
谷峻輔 · 46問 · 2年前ページレイアウト、リストビュー、レコードタイプ、プロセス
ページレイアウト、リストビュー、レコードタイプ、プロセス
46問 • 2年前標準オブジェクト
標準オブジェクト
谷峻輔 · 42問 · 2年前標準オブジェクト
標準オブジェクト
42問 • 2年前ServiceCloud
ServiceCloud
谷峻輔 · 16問 · 2年前ServiceCloud
ServiceCloud
16問 • 2年前ユーザ、ライセンス、プロファイル、権限セット
ユーザ、ライセンス、プロファイル、権限セット
谷峻輔 · 41問 · 2年前ユーザ、ライセンス、プロファイル、権限セット
ユーザ、ライセンス、プロファイル、権限セット
41問 • 2年前データインポート、エクスポート
データインポート、エクスポート
谷峻輔 · 3回閲覧 · 12問 · 2年前データインポート、エクスポート
データインポート、エクスポート
3回閲覧 • 12問 • 2年前Chatter
Chatter
谷峻輔 · 21問 · 2年前Chatter
Chatter
21問 • 2年前承認申請
承認申請
谷峻輔 · 15問 · 2年前承認申請
承認申請
15問 • 2年前フロー
フロー
谷峻輔 · 44問 · 2年前フロー
フロー
44問 • 2年前レポート、ダッシュボード
レポート、ダッシュボード
谷峻輔 · 65問 · 2年前レポート、ダッシュボード
レポート、ダッシュボード
65問 • 2年前SalesCloud
SalesCloud
谷峻輔 · 18問 · 2年前SalesCloud
SalesCloud
18問 • 2年前標準機能
標準機能
谷峻輔 · 72問 · 2年前標準機能
標準機能
72問 • 2年前宣言的開発
宣言的開発
谷峻輔 · 8問 · 2年前宣言的開発
宣言的開発
8問 • 2年前アクセスレベル
アクセスレベル
谷峻輔 · 52問 · 2年前アクセスレベル
アクセスレベル
52問 • 2年前数式、人力規則
数式、人力規則
谷峻輔 · 17問 · 2年前数式、人力規則
数式、人力規則
17問 • 2年前データ型変換
データ型変換
谷峻輔 · 22問 · 2年前データ型変換
データ型変換
22問 • 2年前オブジェクト、項目
オブジェクト、項目
谷峻輔 · 89問 · 2年前オブジェクト、項目
オブジェクト、項目
89問 • 2年前アプリ、タブ
アプリ、タブ
谷峻輔 · 100問 · 2年前アプリ、タブ
アプリ、タブ
100問 • 2年前自動化
自動化
谷峻輔 · 18問 · 2年前自動化
自動化
18問 • 2年前組織、開発モデル
組織、開発モデル
谷峻輔 · 60問 · 2年前組織、開発モデル
組織、開発モデル
60問 • 2年前ボタン、アクション
ボタン、アクション
谷峻輔 · 69問 · 2年前ボタン、アクション
ボタン、アクション
69問 • 2年前インテグレーション
インテグレーション
谷峻輔 · 40問 · 2年前インテグレーション
インテグレーション
40問 • 2年前ページレイアウト、リストビュー、レコードタイプ、プロセス
ページレイアウト、リストビュー、レコードタイプ、プロセス
谷峻輔 · 44問 · 2年前ページレイアウト、リストビュー、レコードタイプ、プロセス
ページレイアウト、リストビュー、レコードタイプ、プロセス
44問 • 2年前標準オブジェクト
標準オブジェクト
谷峻輔 · 32問 · 2年前標準オブジェクト
標準オブジェクト
32問 • 2年前ServiceCloud
ServiceCloud
谷峻輔 · 17問 · 2年前ServiceCloud
ServiceCloud
17問 • 2年前ユーザ、ライセンス、プロファイル、権限セット
ユーザ、ライセンス、プロファイル、権限セット
谷峻輔 · 18問 · 2年前ユーザ、ライセンス、プロファイル、権限セット
ユーザ、ライセンス、プロファイル、権限セット
18問 • 2年前データインポート、エクスポート
データインポート、エクスポート
谷峻輔 · 11問 · 2年前データインポート、エクスポート
データインポート、エクスポート
11問 • 2年前Chatter
Chatter
谷峻輔 · 21問 · 2年前Chatter
Chatter
21問 • 2年前一時
一時
谷峻輔 · 89問 · 2年前一時
一時
89問 • 2年前一時2
一時2
谷峻輔 · 29問 · 2年前一時2
一時2
29問 • 2年前js9 ドキュメント
js9 ドキュメント
谷峻輔 · 80問 · 2年前js9 ドキュメント
js9 ドキュメント
80問 • 2年前問題一覧
1
String.fromCodePoint と str.codePointAt はサロゲートペアを正しく扱う稀なメソッドです
2
マーク文字を付与した際に比較を確実に行うために正規化する。 具体的には、正規化されると、一つの文字として扱われるようになる 詳細は以下 多くの言語では、上/下にマークを持つ基本文字で構成される記号があります。 例えば、文字 a は àáâäãåā のベースの文字です。最も一般的な “複合” 文字は、UTF-16テーブルに独自のコードを持っています。 任意の複合文字をサポートするため、UTF-16 ではいくつかのユニコード文字を使うことができます。ベース文字とそれを “装飾” する1つまたは複数の “マーク” 文字です。 以下のように Sのベース文字に対し、マーク文字を複数付与できる。 let s1 = 'S\u0307\u0323'; // Ṩ, S + 上のドット + 下のドット let s2 = 'S\u0323\u0307'; // Ṩ, S + 下のドット + 上のドット alert( `s1: ${s1}, s2: ${s2}` ); alert( s1 == s2 ); // false (文字は同一に見えますが) これを解決するために正規化が用意された。
3
str.normalize() で実装されています。 記号 Ṩ の場合 alert( "S\u0307\u0323".normalize() == "S\u0323\u0307".normalize() ); // true 例の場合、normalize() は実際に3つの文字の並び(ベース文字とマーク文字2つ)を1つの文字 \u1e68 (S と2つのドット)にまとめています。 alert( "S\u0307\u0323".normalize().length ); // 1 alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true
4
str.trim() – 文字列の最初と最後のスペースを除去します。 str.repeat(n) – 文字列を n 回繰り返します。
5
JavaScript では文字列はイミュータブル(不変)なので、最初の文字を “置換” することはできません。 しかし、既存のものをベースに、最初の文字が大文字化された新しい文字列を作ることはできます。: let newStr = str[0].toUpperCase() + str.slice(1); が、そこには少し問題があります。str が空の場合、str[0] は未定義です。なのでエラーになります。 function ucFirst(str) { if (!str) return str; return str[0].toUpperCase() + str.slice(1);
6
配列では、要素の順序を管理するためのメソッドが提供されているため、順序付けされたコレクションを格納するのに適している。
7
let arr = new Array(); let arr = []; 配列はどんな型の要素も格納することができます。 // 値の混在 let arr = [ 'Apple', { name: 'John' }, true, function() { alert('hello'); } ]; // インデックス 1 のオブジェクトを取得し、その名前を表示 alert( arr[1].name ); // John // インデックス 3 の関数を取得し、実行 arr[3](); // hello
8
問題ない 配列は、オブジェクトのようにカンマで終わる場合があります: let fruits = [ "Apple", "Orange", "Plum", ]; すべての行が同じようになるので、“末尾のカンマ” は項目の挿入や削除が容易になります。
9
list.pop() let fruits = ["Apple", "Orange", "Pear"]; alert( fruits.pop() ); // "Pear" を削除し alert する alert( fruits ); // Apple, Orange list.push(...)※複数要素にも対応 let fruits = ["Apple", "Orange"]; fruits.push("Pear"); alert( fruits ); // Apple, Orange, Pear
10
list.shift() let fruits = ["Apple", "Orange", "Pear"]; alert( fruits.shift() ); // Apple を削除し alert する alert( fruits ); // Orange, Pear list.unshift(...)※複数要素にも対応 let fruits = ["Orange", "Pear"]; fruits.unshift('Apple'); alert( fruits ); // Apple, Orange, Pear
11
ベースはオブジェクト なので、任意のプロパティの追加もできる。 ただし非推奨! let fruits = []; // 配列を作ります fruits[99999] = 5; // その length よりも非常に大きなインデックスでプロパティを割り当てます fruits.age = 25; // 任意の名前でプロパティを作成します
12
push/popのほうがよい shift/unshift の場合は、先頭を削除してから、インデックスの再割り当てが必要なので遅い ↑配列が大きいほど遅くなる
13
配列のための for..of という別のループの形式があります: let fruits = ["Apple", "Orange", "Plum"]; // 配列要素の反復処理 for (let fruit of fruits) { alert( fruit ); } ↑値をとりだしてループ処理を行う もちろんオブジェクトでも使える
14
1 for..in は数値のものだけでなく、 全てのプロパティ を繰り返し処理します。 なので、配列に似たオブジェクトなどで、余分なプロパティが混じる可能性あり。 ブラウザや他の環境では 配列のように見える いわゆる “配列のような” オブジェクトがあります。つまり、それらは length とインデックスプロパティを持っています。しかし、それらは通常は必要のない他の非数値プロパティやメソッドも持っています。for..in ループはそれらもリストします。なので、もし配列のようなオブジェクトを処理する必要があるとき、それらの “余分な” プロパティが問題になる場合があります。 2 配列に最適化されてないため遅い for..in ループは配列ではなく、汎用オブジェクトに対して最適化されているため、10から100倍遅くなります。もちろんそれでもとても速いです。高速化はボトルネックの場合にのみ問題なり、それ以外ではさほど重要でないこともあります。しかしそれでも私たちは違いに気をつけるべきです。
15
配列を変更したとき、length プロパティは自動的に更新されます。正確には、それは配列の実際の値の数ではなく、最大の数値インデックスに1を加えたものです。 例えば、大きなインデックスの1つの要素は大きなlengthを返します: let fruits = []; fruits[123] = "Apple"; alert( fruits.length ); // 124 通常、そのように配列を使わないことに注意してください。
16
length プロパティの別の興味深い点は、書き込み可能と言う点です。 手動で増やした場合、面白いことは起きません。しかし、それを減らしたとき、配列は切り捨てられます。この処理は不可逆です。これはその例です: let arr = [1, 2, 3, 4, 5]; arr.length = 2; // 2つの要素に切り捨てる alert( arr ); // [1, 2] arr.length = 5; // length を戻す alert( arr[3] ); // undefined: 値は返ってきません なので、配列をクリアする最もシンプルな方法は arr.length = 0; です
17
配列は、要素のカンマ区切りのリストを返す独自の toString メソッドの実装を持ってます。 let arr = [1, 2, 3]; alert( arr ); // 1,2,3 alert( String(arr) === '1,2,3' ); // true
18
== で比較しないでください オブジェクトと同様の動作、つまり プリミティブへの変換が行われる。 == の引数の一方がオブジェクトで、もう一方がプリミティブの場合、プリミティブに変換されます。 ちなみに厳密比較 === は、型変換をしないためよりシンプルです。 なので、== で配列を比較する場合、全く同じ配列を参照している2つの変数を比較しない限り、決して等価にはなりません。 例: alert( [] == [] ); // false alert( [0] == [0] ); // false プリミティブとの比較では、以下のように、一見すると奇妙な結果がでることがあります: alert( 0 == [] ); // true alert('0' == [] ); // false ここでは、両方のケースで配列オブジェクトとプリミティブを比較しています。なので、配列 [] は比較のためにプリミティブに変換され、空文字 '' になります。 そこから、0と比較する場合は、空文字から0に変換されてtrueとなる。
19
呼び出し arr[2]() は、構文的には古き良き obj[method]() であり、arr が obj の役割を、2 が method の役割を持っています。 従って、arr[2] の関数をオブジェクトメソッドとして呼び出します そのため、答えは以下となる。 // "a","b",function
20
削除する場合、配列のインデックス移動などの操作が必要なので、deleteは使わない。 arr.splice(str) メソッドを利用する。 追加、削除、また要素の挿入もできるメソッドである。※副作用あり 消す位置と消す個数をきめて、あとは入れる要素をわたせる 構文: arr.splice(index, deleteCount, elem1, ..., elemN) 位置 index から始まります。 deleteCount の要素を削除した後、その場所に elem1, ..., elemN を挿入します。このメソッドは削除した要素の配列を返します。 このメソッドは例で簡単に把握できます。 次の例では、3つの要素を削除し、他の2つの要素でそれらを置き換えます: let arr = ["I", "study", "JavaScript", "right", "now"]; // 最初の 3 要素を削除し、別のものに置換 arr.splice(0, 3, "Let's", "dance"); alert( arr ) // 今は ["Let's", "dance", "right", "now"] splice メソッドは削除せずに挿入することも可能です。 負のインデックスも許容します let arr = [1, 2, 5]; // インデックス -1 (末尾から1つ前) から // 削除 0 要素, // その後 3 と 4 を挿入 arr.splice(-1, 0, 3, 4); alert( arr ); // 1,2,3,4,5
21
arr.slice(start, end) 文字列といっしょ let arr = ["t", "e", "s", "t"]; alert( arr.slice(1, 3) ); // e,s (1 から 3 をコピー) alert( arr.slice(-2) ); // s,t (-2 から末尾まで)
22
引数なし arr.slice() でも呼び出すことができ、これは arr のコピーを生成します。 これは、オリジナルの配列に影響を与えない形でさらに変換するためのコピーを取得するのによく使用されます。
23
メソッド arr.concat は配列を他の配列またはアイテムと結合します。 構文: arr.concat(arg1, arg2...) 任意の数の引数(配列または値)を許容します。 結果は arr, 次に arg1, arg2 などのアイテムを含む新しい配列を返します。 ※arr自体は変わらない もし、引数が配列、もしくは Symbol.isConcatSpreadable プロパティを持っている場合、その全ての要素がコピーされます。そうでない場合、引数自体がコピーされます。 let arr = [1, 2]; // arr と [3,4] をマージ alert( arr.concat([3, 4])); // 1,2,3,4 // arr と [3,4] と [5,6] をマージ alert( arr.concat([3, 4], [5, 6])); // 1,2,3,4,5,6 // arr と [3,4] をマージ後, 5 と 6 を追加 alert( arr.concat([3, 4], 5, 6)); // 1,2,3,4,5,6 オブジェクトを追加する場合、要素としてそのまま追加されてしまうが、 オブジェクトに対してSymbol.isConcatSpreadableプロパティを追加することで、配列ライクなオブジェクトとしてふるまうことができ、Concatされた時に、length以外のプロパティを結合対象とすることができる。 let arr = [1, 2]; let arrayLike = { 0: "something", 1: "else", [Symbol.isConcatSpreadable]: true, length: 2 }; alert( arr.concat(arrayLike) ); // 1,2,something,else ↑もし、 [Symbol.isConcatSpreadable]が定義されてなかったら、// 1,2,[object Object]になる。
24
arr.forEach メソッドは配列の全要素に対して関数を実行することができます。 構文: arr.forEach(function(item, index, array) { // ... item に対して何か処理をする }); 例えば、これは配列の各要素を表示します: // 各要素は alert を呼び出す ["Bilbo", "Gandalf", "Nazgul"].forEach(alert); この場合はalert関数は引数itemだけを受け取る ["Bilbo", "Gandalf", "Nazgul"].forEach((item, index, array) => { alert(`${item} is at index ${index} in ${array}`); });
25
メソッド arr.indexOf, arr.lastIndexOf と arr.includes は文字列の場合と同じ構文を持ち、基本的に同じことを行いますが、文字の代わりにアイテムを操作します: arr.indexOf(item, from) はインデックス from から item を探し、見つかった場所のインデックスを返します。そうでない場合は -1 になります。 arr.lastIndexOf(item, from) は同じですが、右から左に見ていきます。 arr.includes(item, from) はインデックス from から item を探し、見つかった場合、true を返します。 let arr = [1, 0, false]; alert( arr.indexOf(0) ); // 1 alert( arr.indexOf(false) ); // 2 alert( arr.indexOf(null) ); // -1 alert( arr.includes(1) ); // true これらのメソッドは厳密な比較、 === 比較を使うことに留意してください! もしも false を探す場合、ゼロではなく、正確な false を見つけようとします。 また、includes の非常に小さな違いは、indexOf/lastIndexOf と違い、NaN を正しく処理することができます: const arr = [NaN]; alert( arr.indexOf(NaN) ); // -1 (0 になるべきですが, === 等値は NaN では機能しません) alert( arr.includes(NaN) );// true (正しい)
26
arr.find メソッド、※arr.findIndex メソッドもある 構文はこうです: let result = arr.find(function(item, index, array) { // true が返却されると、item が返却され、イテレーションは停止します // 偽の場合は undefined です }); 関数は配列の要素毎に繰り返し呼ばれます: item は要素です。 index はインデックスです。 array は配列自身です。 もし true を返すと、検索が止まり、item が返却されます。見つからない場合は undefined になります。 例 let users = [ {id: 1, name: "John"}, {id: 2, name: "Pete"}, {id: 3, name: "Mary"} ]; let user = users.find(item => item.id == 1); alert(user.name); // John arr.findIndex メソッドは基本的に同じです。が、要素自体ではなく要素が見つかったインデックスを返します。
27
検索結果の要素が複数になる可能性がある場合、arr.filter(fn) を使います。 filter はマッチしたすべて要素の配列を返します: let results = arr.filter(function(item, index, array) { // true の場合、item は results にプッシュされ、イテレーションは継続します // 何も見つからない場合は、空配列を返します }); 例: let users = [ {id: 1, name: "John"}, {id: 2, name: "Pete"}, {id: 3, name: "Mary"} ]; // 最初の2人のユーザの配列を返します let someUsers = users.filter(item => item.id < 3); ※アロー関数は1行ならreturnキーワードを省略できる 上の例はBooleanを返している alert(someUsers.length); // 2
28
arr.map メソッド これは、配列の各要素に対して関数を呼び出し、結果の配列を返します。 構文は次の通りです: let result = arr.map(function(item, index, array) { // item の代わりに新しい値を返します }) 例えば、ここでは各要素をその長さに変換します: let lengths = ["Bilbo", "Gandalf", "Nazgul"].map(item => item.length) alert(lengths); // 5,7,6
29
メソッド arr.sort は配列を 決まった位置に ソートし、要素の順番を変更します。 これもソートされた配列を返しますが、arr 自身が変更されるので、返却値は通常無視されます。 ※副作用あり! 関数を渡さない場合は、 文字列に変換されてソートされる。 let arr = [ 1, 2, 15 ]; // このメソッドは arr の内容を並べ替え(てそれを返します) arr.sort(); alert( arr ); // 1, 15, 2←文字列としてソートされた 関数を渡す場合は、 引数二つとる関数を用意する必要がある。 ちなみにa bに入ってくる値は 最適化されたクイックソートアルゴリズムによって選出された二つの要素ということになる。 返却値に関しては、 0より上なら、aをbのあとに並び替える 0より下なら、aをbのまえに並び替える(そのまま) 0なら、そのまま a>b return 1で昇順とおぼえる! なので b aになる! function compareNumeric(a, b) { if (a > b) return 1; if (a == b) return 0; if (a < b) return -1; } let arr = [ 1, 2, 15 ]; arr.sort(compareNumeric); alert(arr); // 1, 2, 15 もっと簡単に記載するとこうなる let arr = [ 1, 2, 15 ]; //aが大きい場合は正の数となり、順番が入れ替わり、bが大きい場合は負の数となりそのまま。 arr.sort( (a, b) => a - b ); alert(arr); // 1, 2, 15
30
str.localeCompare(str2) を利用する これは、 言語規則に従って、str が str2 より大きい場合、1 を返します。 str が str2 より小さい場合は -1 を返します。 それらが等価な場合は 0 を返します。 という関数なのでそのまま利用できる。 let countries = ['Österreich', 'Andorra', 'Vietnam']; alert( countries.sort( (a, b) => a > b ? 1 : -1) ); // Andorra, Vietnam, Österreich (間違い) alert( countries.sort( (a, b) => a.localeCompare(b) ) ); // Andorra,Österreich,Vietnam (正しい!)
31
メソッド arr.reverse は arr 内の要素の順序を逆転させます。 ※副作用あり 例: let arr = [1, 2, 3, 4, 5]; arr.reverse(); alert( arr ); // 5,4,3,2,1 また、反転後に配列 arr を返します。
32
str.split(delim) メソッドは、与えられた区切り文字 delim で文字列を配列に分割します。 let names = 'Bilbo, Gandalf, Nazgul'; let arr = names.split(', '); for (let name of arr) { alert( `A message to ${name}.` ); // A message to Bilbo }
33
split(s) を呼び出すとき、sを空にすると、文字列を文字の配列に分割します: let str = "test"; alert( str.split('') ); // t,e,s,t
34
arr.join(str) は split と逆を行います。arr のアイテムを str で繋いだ文字列を作ります。 例: let arr = ['Bilbo', 'Gandalf', 'Nazgul']; let str = arr.join(';'); alert( str ); // Bilbo;Gandalf;Nazgul
35
メソッド arr.reduce と arr.reduceRight は、配列に基づいて単一の値を計算するために使用されます。 arr.reduceRight メソッドは右側の要素から計算していくだけの違い。 構文: let value = arr.reduce(function(accumulator, item, index, arr) { // ... }, initial); 関数は各要素に順番に適用され、その結果を次の呼び出しに “引き継ぎ” ます: initial は省略可能だが、記載したほうがよいとされている 引数: accumulator – 前の関数呼び出しの結果で、初回は initial と等価です(initial が指定されている場合) item – 現在の配列の項目です。 index – 位置です。 arr – 配列です。 関数が適用されると、前の関数呼び出しの結果が、次の関数呼び出しの最初の引数として渡されます。 let arr = [1, 2, 3, 4, 5]; let result = arr.reduce((sum, current) => sum + current, 0); ↑0はinitial、つまり初期値のこと alert(result); // 15 0+1 1+2 3+3 6+4 10+5 てかんじで足し合わされてった感じ。
36
初期値が指定されていない場合、reduce は配列の最初の要素を初期値とみなし、2つ目の要素から繰り返し処理を始める。 そのため空配列を初期値なしで処理しようとすると、エラーとなるらしい 従って、常に初期値を指定することをおすすめします
37
配列は別の言語の型を形成していないため Objectとなる!
38
メソッド Array.isArray(value) があります。これは、value が配列のときに true を、そうでない場合には false を返します。 alert(Array.isArray({})); // false alert(Array.isArray([])); // true
39
まず、sortはサポートしてなくて、 find、filter、mapとかでサポートしているらしい。 配列メソッドは渡された関数を実行するが、その際メソッド実行ではなく関数実行となってしまうので、内部のthisの値がグローバルオブジェクトを指してしまう。 これを回避するため、thisArgパラメータでthisの値を明示的にバインドする。 let army = { minAge: 18, maxAge: 27, //booleanを返すメソッド canJoin(user) { return user.age >= this.minAge && user.age < this.maxAge; } }; let users = [ {age: 16}, {age: 20}, {age: 23}, {age: 30} ]; // army.canJoin関数に各userが渡されて関数実行される。 let soldiers = users.filter(army.canJoin, army); alert(soldiers.length); // 2 alert(soldiers[0].age); // 20 alert(soldiers[1].age); // 23 もし上の例で users.filter(army.canJoin) としていた場合、army.canJoin はスタンドアローンの関数として呼び出されるため、this=undefined であり、即時エラーになります。
40
関数を直接渡すのではなく、緩衝材として関数を作り、そこでメソッド実行してやるとよい。 呼び出し users.filter(army.canJoin, army) は users.filter(user => army.canJoin(user)) に置き換え可能である。 多くの人にとってより理解しやすいので、後者の方がよく利用されます。
41
arr.some(fn)/arr.every(fn) は配列の各要素に対してチェックを行い、真偽値を返す。 引数の関数には各要素のvalueとindexが引数としてとることができる。 valueの値をチェックして真偽値を返す関数を定義する。 someは|| every は&&として使える。 もし fn が真の値を返す場合、arr.some() はすぐに true を返し、残りの項目に対するイテレーションを停止します。 偽なら次のイテレーションへ。 fn が偽の値を返す場合は、arr.every() はすぐに false を返し、同様に残りの項目のイテレーションは停止します。 every は配列を比較するのに使えます: function arraysEqual(arr1, arr2) { // 配列の長さが同じであること、 arr1の値が、arr2の同じインデックスの値と全ての要素で同じなら trueを返す。 一個でも違えばfalseを返す。 return arr1.length === arr2.length && arr1.every((value, index) => value === arr2[index]); } alert( arraysEqual([1, 2], [1, 2])); // true
42
良い問題なのでやれ コツはプロパティの配列でメソッドを管理している。 この配列にはメソッドを追加できるので、拡張可能としている。 キャルクレートメソッドを起動することで、引数に合わせたメソッドを配列から起動する感じ
43
問題あり、上記の問題はreturnを省略しており、さらに、オブジェクトリテラルのカッコは処理部分の省略されたカッコであると解釈されてしまう。 なので、結果はこうなる。 const res = [1,2,3].map(i => {res: i}) console.log(res) [ undefined, undefined, undefined ] 対策する場合は、returnを利用する const res = [1,2,3].map(i => { return { res: i } }) console.log(res) [ {res: 1}, {res: 2}, {res: 3} ] それか、丸括弧でオブジェクトリテラルをかこむ const res = [1,2,3].map(i => ({res: i})) console.log(res) [ {res: 1}, {res: 2}, {res: 3} ]
44
for..of ループが使用できるオブジェクトのこと
45
range を 反復可能(iterable) にするために (for..of を動作させるために)は、Symbol.iterator というメソッドをオブジェクトに追加する必要がある。 以下の特性がある。 for..of が始まると、そのメソッドを呼び出します(なければエラーになります)。 メソッドは iterator (メソッド next をもつオブジェクト)を返さなければいけません。 for..of が次の値を必要とするとき、そのオブジェクトの next() を呼びます。 next() の結果は {done: Boolean, value: any} の形式でなければなりません。 そして done=true は繰り返しが終わったことを示します。 そうでない場合は、value は新しい値である必要があります。 これは range の完全な実装です: let range = { from: 1, to: 5 }; // 1. for..of の呼び出しは、最初にこれを呼び出します range[Symbol.iterator] = function() { // ...これは iterator オブジェクトを返します: // 2. 以降、for..of はこのイテレータでのみ機能し、次の値を要求します return { current: this.from, last: this.to, // 3. for..of ループにより、各繰り返しで next() が呼ばれます next() { // 4. オブジェクト {done:.., value :...} を返す必要があります if (this.current <= this.last) { return { done: false, value: this.current++ }; } else { return { done: true }; } } }; }; // これで動作します! for (let num of range) { alert(num); // 1, 2, 3, 4, 5 } 反復可能(iterables)の中心的な機能に注目してください。関心の分離です。 range 自身は next() メソッドを持っていません。 代わりに、別のオブジェクト、いわゆる “イテレータ” は range[Symbol.iterator]() の呼び出しで生成され、反復を処理します。 従って、反復オブジェクトは反復処理されるオブジェクトから分離されています。
46
rangeオブジェクトにnext()を実装する。 同時に[Symbol.iterator]メソッドを定義し、自身を返す。 let range = { from: 1, to: 5, [Symbol.iterator]() { this.current = this.from; // 自身を返す。 return this; }, next() { if (this.current <= this.to) { return { done: false, value: this.current++ }; } else { return { done: true }; } } }; for (let num of range) { alert(num); // 1, そして 2, 3, 4, 5 }
47
欠点は、オブジェクトに対して同時に2つの for..of ループを実行することは不可能だということです。 イテレータ が1つしかないので、オブジェクトは繰り返し状態を共有します。 ですが、2つの並列 for-of はたとえ非同期のシナリオにおいてもまれです。
48
先ほどの例では、range.to = Infinity にすることで、range が無限大になります。 next でdone:trueにせず、valueの値を常に生成しつづけることも可能。 それで、擬似乱数の無限のシーケンスを生成する反復可能なオブジェクトを作ることができます。 もちろん、このような反復可能なオブジェクトに対する for..of ループはエンドレスですが、break を使っていつでも止めることができます。
49
文字列 for (let char of "test") { // 文字ごとに1回、計4回実行します。 alert( char ); // t, 次に e, 次に s, そして t } そしてサロゲートペアも正しく動作します! let str = '𝒳😂'; for (let char of str) { alert( char ); // 𝒳, そして次は 😂 }
50
let str = "Hello"; // for (let char of str) alert(char); // と同じことをしています //イテレータを取得 let iterator = str[Symbol.iterator](); while (true) { // nextメソッドを呼び出し let result = iterator.next(); // doneがtrueならループを抜ける if (result.done) break; alert(result.value); // 1つずつ文字を出力します }
51
反復可能(Iterables) は上で説明したように、Symbol.iterator メソッドを実装したオブジェクトです。 配列ライク(Array-likes) は、インデックスと length を持ったオブジェクトです。なので、これらは配列のように見えます。 例えば、文字列は 反復可能(iterable) (for..of が動作する) であり、かつ 配列ライク(array-like) (数値インデックスと length を持っています) です。
52
Array.from メソッドがあります。 これは 反復可能(iterable) または 配列ライク(array-like) な値を引数に取り、そこから “本当の” Array を作ります。 それ以降、配列のメソッドを呼べるようになります。 let arrayLike = { 0: "Hello", 1: "World", length: 2 }; let arr = Array.from(arrayLike); // (*) alert(arr.pop()); // World (メソッドが動作します) 行 (*) の Array.from はオブジェクトを取り出し、反復可能(iterable) か 配列ライク(array-like) なのか調べ、新しい配列を作りすべてのアイテムをコピーします。
53
2つ目の引数 mapFn を利用する。 Array.from の完全な構文では、オプションで “マッピング” 関数を指定できます: Array.from(obj[, mapFn, thisArg]) ↑[]の間は任意って意味 2つ目の引数 mapFn は、配列に追加する前に各要素に適用する関数であり、thisArg はそこでの this を指定できます。 // range は前問の例で利用したものと仮定 // 各数値の平方 let arr = Array.from(range, num => num * num); alert(arr); // 1,4,9,16,25 まーMap関数があるしあんまおぼえなくていいかも
54
文字列を文字配列に変換するために Array.from を使います: let str = '𝒳😂'; // str を文字の配列に分割します let chars = Array.from(str); alert(chars[0]); // 𝒳 alert(chars[1]); // 😂 alert(chars.length); // 2 str.split とは違い、文字の反復可能な性質に依存するため、for..of のようにサロゲートペアでも正しく動作します。 技術的には、これは以下と同じことをしています: let str = '𝒳😂'; let chars = []; // Array.from は内部では同じループをします for (let char of str) { chars.push(char); } alert(chars); …が、より短く書けます。 これを活用することで、 サロゲートを意識した slice を実装することもできます!
55
Map は Object と同じように、キー付されたデータ項目の集まりです。主な違いは Map は任意の型のキーを許可することです。 もちろんオブジェクトもキーにできる。 オブジェクトとは違い、キーは文字列には変換されません。任意の型のキーが利用可能です。 let map = new Map(); map.set('1', 'str1'); // 文字列キー map.set(1, 'num1'); // 数値キー map.set(true, 'bool1'); // 真偽値キー // 通常のオブジェクトを覚えていますか?キーを文字列に変換していました。 // Map は型を維持します。なので、これらは別ものです: alert( map.get(1) ); // 'num1' alert( map.get('1') ); // 'str1' alert( map.size ); // 3 繰り返しは値が挿入された順で行われます。通常の Object とは違い、Map はこの順番を保持しています
56
map.set(key, value) – キーで、値を格納します. map 自身を返すので、呼び出しを “チェーン” することができます: map.set('1', 'str1') .set(1, 'num1') .set(true, 'bool1'); map.get(key) – 指定されたキーの値を返却します。map に存在しない key の場合には undefined になります. map.has(key) – キーが存在する場合に true を返します。そうでなければ false になります. map.delete(key) – キーで値を削除します. map.clear() – map をクリアします. map.size – 現在の要素の数です.
57
できるけど非推奨 キーが 文字列とシンボルキーでしか使えない これは map を通常の JavaScript オブジェクトとして扱っているので、対応するすべての制限(文字列/シンボルキーのみなど)があることを意味します。
58
オブジェクトで、キーにオブジェクトは使えない。 なので、そのオブジェクトは自動で文字列に変換される。 つまり、 "[object Object]"がキーとなる。
59
等価のテストをするために、Map は SameValueZero アルゴリズムを使います。大雑把には厳密等価 === と同じですが、違いは NaN は NaN と等しいとみなされる点です。なので、NaN も同様にキーとして使うことができます。
60
map.keys() – キーに対する iterable を返します。 map.values() – 値に対する iterable を返します。 map.entries() – エントリ [key, value](配列) の iterable を返します。これは for..of でMapオブジェクトを指定すると暗黙的に使われます。 let recipeMap = new Map([ ['cucumber', 500], ['tomatoes', 350], ['onion', 50] ]); // キー(野菜)の反復 for (let vegetable of recipeMap.keys()) { alert(vegetable); // cucumber, tomateos, onion } // 値(量)の反復 for (let amount of recipeMap.values()) { alert(amount); // 500, 350, 50 } // [key, value] エントリーの反復 for (let entry of recipeMap) { // recipeMap.entries() と同じ alert(entry); // cucumber,500 (など) } ※ちなみに。。 Map は Array と同じように、組み込みの forEach メソッドを持っています。 // 各 (key, value) ペアに対して関数を実行 recipeMap.forEach( (value, key, map) => { alert(`${key}: ${value}`); // cucumber: 500 etc });
61
new Mapで、 キー/値のペア(配列)をもつ、配列またはイテラブルを渡すと生成できる。 // [key, value] ペアの配列 let map = new Map([ ['1', 'str1'], [1, 'num1'], [true, 'bool1'] ]); alert( map.get('1') ); // str1
62
オブジェクトのキー/値のペアの配列を、その形式で返す組み込みのメソッド Object.entries(obj) を使用できます。 なので、次のようにオブジェクトから map の初期化をすることができます: let obj = { name: "John", age: 30 }; let map = new Map(Object.entries(obj)); alert( map.get('name') ); // John ここで、Object.entries はキー/値のペアの配列を返します: [ ["name","John"], ["age", 30] ]。これは Map が必要とするものです。
63
Map から通常のオブジェクトを取得する際に Object.fromEntries が使えます。 これは、キー/値ペアの配列からオブジェクトを生成する。 map.entries()は、マップからキー/値ペアの配列を返すので、これをObject.fromEntriesで読み込むと、オブジェクトになる。 例 let map = new Map(); map.set('banana', 1); map.set('orange', 2); map.set('meat', 4); let obj = Object.fromEntries(map.entries()); // マップからキー/値ペアの配列を生成し、通常のオブジェクトを作成します (*) // 完了! // obj = { banana: 1, orange: 2, meat: 4 } alert(obj.orange); // 2 また、行 (*) をより短くすることもできます: let obj = Object.fromEntries(map); これでもいい。 なぜなら、Object.fromEntries は引数に反復可能なオブジェクトを期待するからです。つまり配列である必要はありません。 そして、map の標準のイテレーションは map.entries() と同じキー/値を返します。 したがって、map と同じキー/値を持つプレーンなオブジェクトが取得できます。
64
Set は、特別タイプのコレクションで、 キーなしで、値のみ。 値は一意という特徴がある Set のイテレーションは常に挿入順で行われます let set = new Set(); let john = { name: "John" }; let pete = { name: "Pete" }; let mary = { name: "Mary" }; // 訪問、何度も来るユーザもいます set.add(john); set.add(pete); set.add(mary); set.add(john); set.add(mary); // set はユニークな値のみをキープします alert( set.size ); // 3 for (let user of set) { alert(user.name); // John (そして Pete と Mary) }
65
new Set(iterable) – set を作ります。オプションで値の配列(任意の iterable が指定可能)からも可能です。 set.add(value) – 値を追加し、 set 自身を返します。 set.delete(value) – 値を削除し、value が呼び出し時に存在すれば true, そうでなければ false を返します。 set.has(value) – set の中に値が存在すれば true を返し、それ以外は false です。 set.clear() – set から全てを削除します。 set.size – set の要素数です。
66
Mapとの互換性が意識されている。 主なメソッドは以下の通り set.keys() – 値に対する iterable なオブジェクトを返します。※キーではないので注意 set.values() – set.keys と処理内容は同じ、Map との互換性のために作られたもの。 set.entries() – [value, value] のエントリのための iterable なオブジェクトを返します。Map の互換性のために存在します。 Set の中の forEach 関数もMapとの互換性が意識されており、 3つの引数を持っています: 値(value), 次に 再び値(valueAgain), 次にターゲットのオブジェクトです。実際、引数には同じ値が2回出現します。 let set = new Set(["oranges", "apples", "bananas"]); for (let value of set) alert(value); // forEach と同じ: set.forEach((value, valueAgain, set) => { alert(value); });
67
オブジェクトをキーとして管理し、 キーは到達可能性を保有しないことが特徴。 WeakMap のキーはプリミティブな値ではなくオブジェクト限定。 オブジェクトをキーとして使用し、そのオブジェクトへの参照がWeakMap以外になかくなった場合、自動的にメモリ(と map)から削除されます。 let john = { name: "John" }; let weakMap = new WeakMap(); weakMap.set(john, "..."); john = null; // 参照を上書きします // john はメモリから削除されます! 通常のMapであれば、johnにnullが代入されたとしても、 Mapのキーでjohn を参照していので到達可能であり、ガベージコレクションの対象とはならないが WeakMapで扱うキーについては、 到達可能性を保有したことにならない! そのため、ガベージコレクションの対象となる
68
WeakMap は繰り返しと、メソッド keys(), values(), entries() をサポートしません。 そのため、すべてのキーや値を取得する方法はありません。 ガベージコレクションによるクリーンアップのタイミングがわからないので、到達可能性がなくても、まだエンティティか残ってる場合がある。 なので、エンティティが生きてるか消えてるか不定なのでサポートしてない。
69
WeakMap は次のメソッドのみを持っています: weakMap.get(key) weakMap.set(key, value) weakMap.delete(key, value) weakMap.has(key)
70
ライブラリ側で、メイン側から渡されるオブジェクトを保持する場合、 WeakMapで保持しておくと、 メイン側で参照をなくした時に、ガベージコレクションの対象とさせることができる。 ライブラリ側 📁 visitsCount.js let visitsCountMap = new WeakMap(); // weakmap: user => visits count // 訪問数を増加 function countUser(user) { let count = visitsCountMap.get(user) || 0; //メイン側で渡されるオブジェクトをWeakMapで管理! visitsCountMap.set(user, count + 1); } メイン側 // 📁 main.js let john = { name: "John" }; countUser(john); // 訪問をカウント // 参照をなくす!=ガベージコレクションの対象となる。 john = null;
71
キャッシュ機能など履歴や実績の管理を実装することができる。 関数からの結果を保持(“キャッシュ”)できるので、同じオブジェクトに対する将来の呼び出しで再利用することができます。 この時WeakMapを利用することによって、キャッシュした値のクリーンアップができるようになる。 // 📁 cache.js let cache = new WeakMap(); // 計算し結果を覚える function process(obj) { //計算済みかどうか判断 if (!cache.has(obj)) { let result = obj /* に対する計算結果 */; cache.set(obj, result); } //計算済みであれば、その時の計算結果を返す return cache.get(obj); } // 📁 main.js let obj = {/* some object */}; let result1 = process(obj); // キャッシュから取得した、記憶された結果が使われます let result2 = process(obj); // ...後ほど、オブジェクトがこれ以上は不要になったとき obj = null; // WeakMap なので cache.size は取得できません // が、0 あるいはすぐに 0 になります // オブジェクトがガベージコレクトされると、キャッシュされたデータも同様に削除されます。
72
WeakMapのSet版 Set とちがい、WeakSet へはオブジェクトのみ追加できる。 WeakMapと同様に到達可能性を保持しない WeakMap と同様 WeakSet も、イテレーションの欠如と現在のすべてのコンテンツを取得することができない。 例えば、ユーザを WeakSet に追加して、サイトにアクセスしたユーザを追跡できます。: let visitedSet = new WeakSet(); let john = { name: "John" }; let pete = { name: "Pete" }; let mary = { name: "Mary" }; visitedSet.add(john); // John が訪問 visitedSet.add(pete); // 次に Pete visitedSet.add(john); // John 再び // visitedSet は 2 ユーザいます // John が訪問したかどうかをチェック alert(visitedSet.has(john)); // true // Mary が訪問したかをチェック alert(visitedSet.has(mary)); // false john = null;
73
Mapと同様のものが用意されている。 しかし、メソッドではなく関数であることが異なる。 Object.keys(obj) – キーの配列を返します。 Object.values(obj) – 値の配列を返します。 Object.entries(obj) – [key, value] ペアの配列を返します。 map.keys()のように、obj.keys()ではないことに注意! 関数 Object.keys(obj)形式である。 また、それぞれの戻り値もiterable ではなく、“本当の” Arrayであることに注意
74
主な理由は柔軟性です。JavaScript ではオブジェクトはすべての複雑な構造のベースであることを忘れないでください。 そのため、独自の order.values() メソッドを実装する order という独自のオブジェクトがあるかもしれません。 それでも Object.values(order) を呼ぶことができます。 ちなみに、 Object.* メソッドが単なる iterable ではなく “本当の” 配列オブジェクトを返すことに関しては、主に歴史的な理由らしい
75
それらを適用したい場合は、Object.fromEntries に続いて、Object.entries が使用できます。: Object.entries(obj) を使用して obj からキー/値ペアの配列を取得します。 その配列で、配列のメソッドを使用します。例えば map 結果の配列で Object.fromEntries(array) を使用して、配列をオブジェクトに戻します。 let prices = { banana: 1, orange: 2, meat: 4, }; let doublePrices = Object.fromEntries( // 配列に変換して map を実行、その後 fromEntries でオブジェクトに戻します Object.entries(prices).map(([key, value]) => [key, value * 2]) ); alert(doublePrices.meat); // 8
76
// 姓名の配列があります let arr = ["John", "Smith"] // 変数へ分割して代入 // 普通のパターン let firstName = arr[0]; let surname = arr[1]; // 上を短く書いたパターン これを分割代入という! let [firstName, surname] = arr; alert(firstName); // John alert(surname); // Smith
77
配列の不要な要素は、余分なカンマをつけることで捨てることができます: // 1番目、2番目の要素が不要の場合 let [, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic"]; alert( title ); // Consul 上のコードでは、最初の2つの要素がスキップされ、3つ目は title に代入され、残りもスキップされています。
78
右辺は任意の反復可能(iterable)に対して動作します …実際には配列だけでなく、任意の反復可能(iterable)に対して使うことができます: let [a, b, c] = "abc"; // ["a", "b", "c"] let [one, two, three] = new Set([1, 2, 3]); 内部的には分割代入は右辺の値に対してイテレーションすることで動作するため、これも動作します。 これは = の右側の値に対して for..of を呼び出し、値を代入するためのシンタックスシュガーの一種です。
79
オブジェクトの key-value をループするのに、分割代入を一緒に使うこともできます: let user = { name: "John", age: 30 }; // key-value のループ for (let [key, value] of Object.entries(user)) { alert(`${key}:${value}`); // name:John, then age:30 }
80
let guest = "Jane"; let admin = "Pete"; // 値を入れかえましょう: guest=Pete, admin=Jane ちなみに右辺は配列を形成してるだけ [guest, admin] = [admin, guest]; alert(`${guest} ${admin}`); // Pete Jane (successfully swapped!) ここでは、2つの変数の一時的な配列を作り、その直後、入れ替えた順番で分割しました。 この方法で2つ以上の変数を入れ替えることも可能です。
81
省略されます。 続く項目もすべて取得したい場合は、3つのドット "..." を使用して “残り” を取得するパラメータを1つ追加します。: 配列で取得される let [name1, name2, ...rest] = ["Julius", "Caesar", "Consul", "of the Roman Republic"]; // rest は3つ目の項目からの配列です alert(rest[0]); // Consul alert(rest[1]); // of the Roman Republic alert(rest.length); // 2 restの値は、残りの配列要素の配列です。 rest の代わりに他の変数名を使用できます。その前に3つのドットがあり、分割代入の最後にくるようにしてください。
82
値が足りない場合は、代入されないので、undefinedとなる。 値がなかった場合に “デフォルト” 値を使いたければ、= を使ってデフォルト値を指定することができます: デフォルト値はより複雑な式や関数呼び出しにすることもできます。それらは値が提供されなかったときのみ評価されます。 例えば、ここでは2つのデフォルトに対して prompt 関数を使っていますが、値がなかった場合のみ実行されます: // 姓のプロンプトのみを実行する let [name = prompt('name?'), surname = prompt('surname?')] = ["Julius"]; alert(name); // Julius (配列から) alert(surname); // プロンプトが得たもの ↑デフォルト値をの評価は値がなかったときのみ!、
83
let {var1, var2} = {var1:…, var2…} 右辺には、変数に分割したい既存のオブジェクトがあります。 左辺には該当するプロパティの “パターン” を指定します。 単純なケースでは、それは {...} に変数名を並べたものです。 例: let options = { title: "Menu", width: 100, height: 200 }; let {title, width, height} = options; alert(title); // Menu alert(width); // 100 alert(height); // 200 プロパティ options.title, options.width と options.height は、該当する変数に代入されます。
84
順番は関係ありません。これも動作します。: // let {...} 内のプロパティ順を変えた場合 let {height, width, title} = { title: "Menu", height: 200, width: 100 } 同名の変数名でマッピングされている!
85
コロンを使うことでセットすることができます: let options = { title: "Menu", width: 100, height: 200 }; // { 元のプロパティ: ターゲットとなる変数 } let {width: w, height: h, title} = options; // width -> w // height -> h // title -> title alert(title); // Menu alert(w); // 100 alert(h); // 200 コロンは “何を: どこに” を示します。
86
コロンと等号の両方を組み合わせることもできます。: let options = { title: "Menu" }; let {width: w = 100, height: h = 200, title} = options; alert(title); // Menu alert(w); // 100 alert(h); // 200
87
配列といっしょ let options = { title: "Menu", height: 200, width: 100 }; // title = title と名前付けられたプロパティ // rest = オブジェクトのプロパティの残り let {title, ...rest} = options; // now title="Menu", rest={height: 200, width: 100} alert(rest.height); // 200 alert(rest.width); // 100
88
オブジェクトリテラルとして右辺を書いているつもりだが、 JavaScriptによってコードブロックと認識されてしまいエラーとなってしまう。 コードブロックとは、以下のような 文をグループ化するために使われます。 { // a code block let message = "Hello"; // ... alert( message ); } コードブロックではないと JavaScript に示すためには、代入全体を括弧 (...) で囲む必要があります: let title, width, height; // これでOKです ({title, width, height} = {title: "Menu", width: 200, height: 100}); alert( title ); // Menu
89
左辺は右辺のパターンにあわせて、 配列なら[] オブジェクトなら{} を利用して分割代入していくことができる。 let options = { size: { width: 100, height: 200 }, items: ["Cake", "Donut"], extra: true }; // わかりやすくするために、複数の行での分割代入 let { size: { // ここにサイズを格納 width, height }, items: [item1, item2], // ここに items を割り当てる title = "Menu" // オブジェクトには存在しない (デフォルト値が使われます) } = options; alert(title); // Menu alert(width); // 100 alert(height); // 200 alert(item1); // Cake alert(item2); // Donut 左辺で言及されていなかった extra を除いた options オブジェクト全体が該当する変数に代入されます。 最終的には、width, height, item1, item2 と、デフォルト値から title を得ます。 代わりに中身を取得しているので、size と items の変数はないことに注意してください。
90
非構造化
91
ある関数が多くのパラメータを持っており、ほどんどがオプションであることがあります。特にユーザインタフェースのときに当てはまります。メニューを作る関数を想像してみてください。幅と高さ、タイトル、アイテムのリストなどを持っています。 ここに、良くない関数の書き方があります: function showMenu(title = "Untitled", width = 200, height = 100, items = []) { // ... } 現実の問題の1つは、どうやって引数の順番を覚えるか、です。コードがしっかりドキュメント化されていれば、通常は IDE が助けてくれます。しかし、他にも問題があります。ほとんどのパラメータがデフォルトでOKの場合の関数の呼び方です。 こうなりますか? // デフォルト値で良い場合は undefined にする showMenu("My Menu", undefined, undefined, ["Item1", "Item2"]) 非常に扱いづらい。。 このようなケースで非構造化を利用する! オブエジェクトとしてパラメータを渡し、関数はそれらを変数に分解します: let options = { title: "My menu", items: ["Item1", "Item2"] }; function showMenu({ title = "Untitled", width: w = 100, // width は w に height: h = 200, // height は h に items: [item1, item2] // items の最初の要素は item1 へ、次は item2 へ }) { alert( `${title} ${w} ${h}` ); // My Menu 100 200 alert( item1 ); // Item1 alert( item2 ); // Item2 } showMenu(options);
92
分割代入は右辺になにもないとエラーとなる。 分割代入は showMenu() に引数があることを前提にしている点に注意してください。もしすべての値をデフォルトにしたい場合には、空のオブジェクトを指定する必要があります: showMenu({}); // OK, すべての値はデフォルト値になります showMenu(); // これはエラーになります
93
非構造化対象全体のデフォルト値に {} を指定することで対応することができます: function showMenu({ title = "Menu", width = 100, height = 200 } = {}) { alert( `${title} ${width} ${height}` ); } showMenu(); // Menu 100 200 上のコードでは、全体の引数オブジェクトがデフォルトで {} なので常に分解する何かがあります。
94
new Date() 引数なし – 現在の日付と時刻で Date オブジェクトを作ります: new Date(milliseconds) Jan 1st of 1970 UTC+0 (1970年 1月1日 UTC+0) からの経過したミリ秒(秒の1/1000)に等しい時間をもつ Date オブジェクトを作ります。 new Date(datestring) 1つの引数でそれが文字列の場合、自動でパースされます。Date.parse アルゴリズム(後述)でパースされます。 new Date(year, month, date, hours, minutes, seconds, ms) ローカルタイムゾーンで、与えられた要素で日付を作成します。最初の2つの引数は必須です。
95
タイムスタンプ
96
ローカルタイムゾーンで取得する タイムゾーン UTC+0 の日、月、年などを返す、UTCカウンターパートもあります:getUTCFullYear(), getUTCMonth(), getUTCDay().
97
getTime() 日付のタイムスタンプを返します – それは、1970年 UTC+0 の 1月1日からの経過ミリ秒です。 getTimezoneOffset() ローカルタイムゾーンとUTCの差を、分で返します: // タイムゾーン UTC-1 にいる場合、60 を出力 // タイムゾーン UTC+3 にいる場合、-180 を出力 alert( new Date().getTimezoneOffset() );
98
自動補正 は Date オブジェクトのとても便利な機能です。私たちが範囲外の値を指定した場合、それは自動的に調節されます。 2013/2/1が出力される。 はみ出した分は自動補正によって、計算される。 つまり、32日が自動補正によってくりあがり、次の月の次の日に補正された。 また、ゼロや負値をセットすることもできます。例えば: let date = new Date(2016, 0, 2); // 2 Jan 2016 date.setDate(1); // 月の1日を設定します alert( date ); date.setDate(0); // 0日はない。最小日は1なので、先月の最後の日になります alert( date ); // 31 Dec 2015
99
Date オブジェクトが数値へ変換されるとき、date.getTime() と同じようにタイムスタンプになります: let date = new Date(); alert(+date); // ミリ秒の数値です, date.getTime() と同じです
100
現在のタイムスタンプを返す特別なメソッド Date.now() があります。 これは、意味的には new Date().getTime() と同じですが、中間の Date オブジェクトを作らないため、より速く、ガベージコレクションに負荷をかけません。 これはおそらくベターです: let start = Date.now(); // 1 Jan 1970 からのミリ秒 // なにかする for (let i = 0; i < 100000; i++) { let doSomething = i * i * i; } let end = Date.now(); // 終了 alert( `The loop took ${end - start} ms` ); // 日付ではなく、数値を減算する