- 概要
- 十六章第十一回 クラス
- 十六章第十二回 クラスの継承
- 十六章第十三回 MapとSet
- 十六章第十四回 Proxy
- 十六章第十五回 Reflect
- 十六章第十六回 ES2015以降の配列
- 十六章第十七回 ES2015以降のObject
- 十六章第十八回 ES2015とプリミティブ
- 十六章第十九回 ES2015の正規表現
- 十六章第二十回 モジュール
- 十六章第二十一回 async/await
- 十六章第二十二回 TC39とJavaScriptの標準化
- 感想
前: JavaScript中級者になろう 16章(前半)を読んだ (ES2015) - t_hazawaの日記
概要
- ES2015(-17) を知った
- ES2018~2022 も何が増えたか項目は見た
- この↓ 24600字ある
十六章第十一回 クラス
https://uhyohyo.net/javascript/16_11.html
- 目玉機能
- これで、継承さんしゅるいめかな かきかた多い
JavaScriptにおけるクラスは、端的にいえばコンストラクタを作る新しい方法
class Foo{ constructor(arg){ this.prop = arg; } }
- いままでもnew 演算子アったよね コンストラクタがあればnew 使えるのかな
ただし、JavaScriptにおいてクラスという概念は本来存在しません その実体は関数(コンストラクタ)です。実際、typeof演算子を使って調べるとtypeof Foo === "function"となる “クラス”は関数
- なるほど classがふえたわけではないのね
クラスとして作られた関数はコンストラクタ専用なので、newをつけずに呼び出すことはできません 関数の役割の明文化の一環
constructorという名前の関数は特別扱いとなり、この関数の処理がコンストラクタの処理となります
昔の方法では、メソッドはprototypeを用いて定義しました。クラスの構文を使うともっと楽に定義することができます。
- どっちのやり方出作ってもできるものは同じっぽい(?)
なんだか懐かしいサンプル
attackメソッドの実体はTeki.prototype.attackにあります。よって、例えばzako.attack === Teki.prototype.attackはtrueになります クラス宣言は我々が第九章で四苦八苦したことを簡単にやってくれる便利な構文
- なるほど。便利になっただけだった。これからは必ずこの構文で書かれることだろう(こっちに寄せるのが良さそう)
クラス宣言の中でメソッドを定義するときは、定義の前にstaticと書くことによりstatic関数を定義することができます。 staticが付いた定義はTeki.prototypeではなくTekiのメソッドとして定義されます。
- さっそく新キャラ登場
staticな定義はインスタンスのメソッドを定義するのではなく、コンストラクタにくっついたメソッドを定義します の機能は、コンストラクタのメソッド(例えばArray.fromとか)を作りたいときに役に立ちます。
- なんか自分の他言語でしってるstaticかんすうとちがうきがする
言語によってはクラスに「privateメソッド」とかいう機能が備わっていますが、それはありません。(ただし、クラス宣言におけるプロパティ定義構文がStage 3、privateメソッド/プロパティはStage 2ですので(2017年10月現在)、ES2018くらいにこれらの機能が追加されるかもしれません。)
- いまも正式な機能としてはなさそう がんばっをユーザがつくってる
クラス宣言は任意のブロックの中に書くことができます。このとき、それにより定義されたクラスはそのブロックをスコープとして持ちます。
クラスの定義はこのようにconstructor関数を省略することができます。その場合、コンストラクタは何もしない関数になります。
クラス式もあります。クラス名を省略できます。
var Foo = class { hello(){ console.log("Hi!"); } };
- むめいくらすだ
コンストラクタは関数なので、返り値を返すこともできます。この場合、実はnewでインスタンスを作った結果がその返り値の値になります。
本当にただの配列であり、Fooのインスタンスではありません。こうなるとFooクラスを作った意味があまり無いような気がします。
クラスの構文は分かりやすく便利なので、オブジェクト指向的なことをするときはぜひ使っていきましょう。
よみおわ 2022/01/02 23:54 18m
2022/01/06 10:58 0m 再開
十六章第十二回 クラスの継承
https://uhyohyo.net/javascript/16_12.html
- いままで行っていた継承をカンンンにできるらしい
class Dragon extends Teki{
- おなじみの構文
- もはや全てこっちの構文で書かれるのだろう
これの裏では、以前解説したprototypeチェーンがちゃんとあります コンストラクタの継承も自動
class Foo extends (class {}){}
- むめいクラスのKE化粧も可能
継承を行った場合、実は静的プロパティ,静的メソッドも継承されます。
super呼び出し
- Dragonのコンストラクタがあるときに親のTekiのコンストラクタを呼びたいときとかに super(name, hp);
一般にコンストラクタではthisのプロパティに代入するなどしてオブジェクトの初期化を行いますが、super呼び出しはthisを触る前である必要があります(thisに全く触らないでもsuperは呼び出す必要があります)
super.メソッド名とすると、親クラスのメソッドを得ることができます(super[文字列]の形でもいいです)
- なんか、 super という名前の変数は作れなさそうだね 予約後が増えてそう
クラスの機能はこれで全てです。今までのjavascriptらしからぬ文法ですがとても便利
- new.target
new.targetは関数の中で使うことができ、newで呼ばれたときはそのときのコンストラクタが入っています
メタプロパティという言葉はfunction.sentの話のときにちらっとでてきました
ひとつの使い方は、関数がnewで呼ばれたのかそうでないのかを判別すること
- 小クラスがなにかを親くらすのコンストラクタが知れるとのこと
yomiowa 23m
十六章第十三回 MapとSet
https://uhyohyo.net/javascript/16_13.html
- 謎のset でもdomら辺で出てきたヤツかな
- Es2015の新文法はほぼおわったらしい
- ここからは新しい組み込みオブジェクト
- ◎setとaddの違いか セットはキーがなさそう
- Setもキーはあるらしい
- >Map・Setではキーにたいして任意の値を使うことができます
- >mapやsetのキーとして使う場合はnanどうしは同じ値と見なされます。
- >今中に何が入っているかという情報が使える
- Weakはいまどんなキーが使われてるか参照できないなう(2022/01/08 11:52:52)
- やっぱりsetはキー無しのようだ https://ja.javascript.info/map-set なう(2022/01/08 11:55:06)
ここまで10.5ふん
- イテラブルを引数にコンストはくとできるマップ
- 便利なnew Map(arr.entries());
- Foreach よりfor-ofの方がナウいらしいなう(2022/01/08 12:20:49)
- Map.@@iteratorがあるので、for-ofでmap自体をしていできるなう(2022/01/08 12:23:48)
17.5ふんなう(2022/01/08 12:24:25) なう(2022/01/08 19:37:48)
- >先ほど、[キー, 値]がMapの基本単位だと述べましたが、Setの場合は値が入っているかどうかという情報しかないので、値そのものが基本単位となります。
2022/01/08 22:21
console.log(s); // Set {"foo", "bar", 3}
- なんか、こんなふうに表されるらしい
console.log(s.has('foo')); // true
valuesメソッドが存在し、これはSetに入っている値をひとつずつ取り出すイテレータを返します
- entries() や keys() もあるとのこと
- もちろん set.@@iterator があるので s 自体がイテレータ
- .forEach() もあるぞ
2022/01/08 22:25 24m yomiowa
十六章第十四回 Proxy
https://uhyohyo.net/javascript/16_14.html
- 驚異の14000時 一つ前は4400時
proxyを紹介します。これはes2015の新しい機能で、動作をカスタマイズしたオブジェクトを作成できる
- set(), get() の進化系らしい
var obj = new Proxy(target, { get(target, name, receiver){ return name; }, });
引数は2つで、第1引数(今回はtarget)はカスタマイズされるオブジェクトです。
第2引数はトラップ (trap)を定義するオブジェクトです。各トラップは関数であり、今回はgetというトラップのみ定義されていることになります
- Proxy を介して、 target を操作できるらしい
ゲッタは各プロパティに対して設定されるもので、そのプロパティに対するアクセスが関数によりカスタマイズできる
- Proxy の getトラップでは、全プロパティへのアクセスを一律でカスタマイズデキるとのこと
役に立つ例としてよく紹介されるのがデフォルト値を持つオブジェクトです
setトラップもあります。 例えば、値は数値しか許さないという厳しいオブジェクト
これはプロパティの値をただ返すのではなく100倍にして返すという見えっ張りなオブジェクトです。
最後のほうの例ではvar target = {};とせずにProxyの第1引数に新しく作ったオブジェクト{}を直接渡しています。こうすることでもとのオブジェクトを隠蔽でき、トラップを介さない操作を防ぐことができるでしょう。
他にも愉快なトラップがいくつもあります。まずはhasトラップ in演算子の挙動に影響を与える あるプロパティがあるオブジェクトの中に存在するかどうか調べる演算子
in演算子しか詐称することができません hasOwnPropertyに対しては無力
- configurable は プロパティごとの属性で、 拡張不可はオブジェクトの属性なのね
proxyといえどもオブジェクトのプロパティに関する諸々を詐称するのは大変
- ownKeys トラップで、キー一覧とかを詐称できる
- getやsetはまぁ使い所が分かった感じ
- 制限が色々と多い
- 一覧の順番を変えたりできる
definePropertyトラップがfalseを返した場合はObject.definePropertyはエラーを発生させます。
33分 7割読んだ 次は まず、拡張不可能オブジェクトに対して
- propertyのdeleteをトラップもデキる 2022/01/10 23:39
- prototype を Array.prototype と詐称したりもできる
Object.setPrototypeOfは紹介していませんでしたね。これはES2015で追加されたメソッドで、その名が示す通りObject.getPrototypeOfの逆で、あるオブジェクトに対応するprototypeオブジェクトを変更できるメソッド このメソッドは気軽に使うべきではありません。本当に必要な場面でのみ使いましょう
- 詐称どころか、prototype を変更もできる
- prototype だとそういうことができるのだなあ
- apply で 関数オブジェクトを関数として呼び出せる
function#applyというのはfunctionのインスタンスが持つapplyメソッド
- apply トラップをツケると、applyでの呼び出しに処理を追加できる
クラスは関数ですがnewを用いた呼び出ししかできない
- construct トラップすると、インスタンスを作らせなくしたりできる
- Proxy.revocable でも Proxyを作れるらしい2022/01/11 0:00 18m
返り値は、proxyとrevokeという2つのプロパティを持ったオブジェクト
- revoke すると、そのproxyは使えなくなる
何らかのトラップが介入できる操作はこのように全てエラーとなります。 トラップの情報を捨てる目的は主にメモリの節約
proxyオブジェクトそのものは必要だけどもう操作しないという稀有な状況が発生しそうで、しかもメモリを節約したいという状況なら使いみちがあるかもしれません。
- Proxyに関係深い Reflect というのがあるらしい
2022/01/11 0:03 22m よみおわ 長かった
十六章第十五回 Reflect
https://uhyohyo.net/javascript/16_15.html
Reflectは組み込みオブジェクト これらのメソッドはオブジェクトの操作に利用することができます
reflectに存在するメソッドはproxyのトラップと一対一で対応しています
// obj.foo と同じ意味 console.log(Reflect.get(obj, 'foo', obj));
- 1つめの引数と3つ目の引数は同じものを渡す…?
reflectのメソッドの特徴は、エラーを発生させない
Object.definePropertyの場合はエラーとなります。一方、Reflect.definePropertyを使うとエラーが発生せず、失敗を表すfalseが返り値として返ってきます。
- なんか、オブジェクトをエラーを発生させずに触るものっぽい?
Reflectのメソッドは失敗してもエラーを発生させたくない場合に適しています。また、明らかにProxyとよく対応していることから、Proxyと一緒に使われることがあります
このようにトラップから「本来の動作」を行いたいという場面は結構あります。。。このような場合にreflectのメソッドを使うと綺麗に書くことができます。 reflectのメソッドに渡す引数はトラップに渡された引数と対応しているので、次のようにできます。
return Reflect.get(target, name, receiver);
- とかけるらしいけど、そんなにメリット感じないぞ…?
- receiverはゲッタセッタ内でthisになるべきオブジェクト
第3引数を省略できます(省略すると第1引数と同じになります)
- Reflect というものがあるのはわかった
十六章第十六回 ES2015以降の配列
https://uhyohyo.net/javascript/16_16.html
13500 字 ながい
es2015では例によって、配列に新しい機能(メソッド)が追加されました
イテレータ系メソッド。 -> fillメソッドは、配列の要素をまとめて変更できる便利なメソッド
- 追加された配列系メソッドの紹介回みたい
第2引数と第3引数で指定された範囲の要素を全て第1引数の値にします。ただし、引数で示される範囲は第2引数(開始位置)の位置から第3引数(終了位置)の直前まで
今まではこのようなことを行いたい場合はループを回すしかなかったので、簡単にできるようになったのは嬉しいですね
-1は最後の要素、-2はその一つ前の要素を指します。配列の最初から、最後の1つを残して全て書き換えたい場合はarr.fill(100,0,-1)とできます
第3引数を省略すると配列の最後まで書き換えられるのは便利です。第2引数と第3引数を両方省略した場合は配列を全部書き換えることになります
var arr=new Array(100);。arr.fill(0,0,100);
- Arrayのコンストラクタは長さなのね
copyWithinメソッドは、配列の要素をまとめてコピーできるメソッド 同じ配列の中である場所から別の場所にコピーする
第2引数(開始位置)から第3引数(終了位置)までの要素を、第1引数(コピー対象位置)の位置にコピーします
- コピー先は上書きされるとのこと
c言語を知っている方は標準ライブラリのmemmove関数を思い出すかもしれません。特にtypedarrayの場合(後述)はそれくらいのパフォーマンスが場合によっては期待できるでしょう。
次に紹介するfindとfindIndexは検索系の便利なメソッド これらのメソッドはindexOfが進化したメソッドです
indexOfは第1引数に検索する値を渡しましたが、findやfindIndexでは関数が渡されます。
true(または真偽値に変換するとtrueになる値)を返す値を見つけたらその値が返されます findIndexは位置
第1引数は判定対象の要素で、第2引数はそのインデックス、第3引数は配列そのもの
includesメソッドは非常に単純です。与えられた値が配列に含まれるならtrue、含まれないならfalseを返します。
indexOfではnanを検索できない includesでの値の一致判定は===とは異なり、NaN同士の一致を正しく判定してくれます。よって、includesを使えばNaNが含まれているかどうか判定できます。
includesが採用している値の一致判定方法は仕様書用語でいえばSameValueZero MapとSetの回でもNaNをキーとして使えるという話題が出ましたが、SameValueZeroはMapやSetで使われている値一致判定方法です。
Arrayの静的メソッド
Array.ofです。これは、引数を任意の数受け取り、それらを要素とする配列を作って返します
- コンストラクタは長さだもんね
これなら[3,5,7]のように配列リテラルを使えばいいような気がしますね。実際その通りなのですが、関数として欲しい場合にはすこし役に立ちます
arrayコンストラクタはもちろん配列を作りますが、その使い方は2種類あります。ひとつは、できる配列の中身を指定する方法です。。。var arr=new Array(3,5,7);
- 引数が1つのときだけかわるのか…
この罠を解消した関数がarray.ofであるとも言えます。
ここでemptyという謎の概念が出てきています
実は、このemptyというのはそもそもその位置にプロパティが存在しないということを意味しています。
- ?
配列はオブジェクトの一種であり、arr[0]のようにアクセスできる配列の各要素もまたプロパティである arrの0番目の要素は、arrというオブジェクトの0というプロパティなのです
長さの範囲内なのにプロパティが存在しないときにその要素がemptyであると呼びます(正式な名前ではなく、そういう慣習があるというだけですが)
- 。emptyを含む配列の作り方 から
var arr=[0,1,,3,,,6]; console.log(arr);//[0,1,empty,3,empty×2,6]
delete演算子でプロパティを消すことでその部分をemptyにするという方法もあります。
- foreach map は empty むし
- for-of は empty 無視しない
es2015の配列メソッドはemptyに対する扱いが素直
型付き配列。。ところで、配列に似たものとして、file apiの回で型付き配列(typed array)を紹介しましたね。。。型付き配列の定義はes2015からecmascript仕様に取り込まれました。 配列のメソッドはtypedarrayでも使えます。便利ですね。
- Uint8Array とか
配列の継承について解説します。クラスの回で説明した通り、es2015では継承が楽に行えるようになっています。実は、配列をはじめとする組み込みオブジェクトも継承できるのです
- 配列を継承してクラスにできるらしい
class SuperArray extends Array{
Array.ofはそれ自身はそこまで意味がありませんでしたが、継承先でも利用できるのは便利です。
- filterとかで配列から新しい配列を作っても、元の配列のクラスのインスタンスになる
@@speciesです。@@speciesがSymbol.speciesのことである
console.log(SuperArray[Symbol.species]); // SuperArray
配列の多くのメソッドはジェネリック性と呼ばれる性質を持ちます。これは、「配列っぽいオブジェクトに対しても動く」 実は配列のメソッドはこのようなオブジェクトがthisとして渡されても動作するようになっています
@@isConcatSpreadable
concatメソッドは、配列に他の配列をつなげて新しい配列を作ることができるメソッドです。 var arr = [1, 2, 3].concat([4, 5], [6, 7, 8], [9]);
var arr = [1, 2, 3].concat([4, 5], 6, 7, [8, 9]);
よみおわ 2022/01/12 23:57 23m
十六章第十七回 ES2015以降のObject
https://uhyohyo.net/javascript/16_17.html
- 今度はObjectだ
- サラットトイうけど 6100文字
objectの機能というのは、つまりobjectの静的メソッドのことです
Object.getOwnPropertySymbolsでした。これはあるオブジェクトが持つプロパティのうち、名前がシンボルであるものを列挙するメソッド
- マニアック
Object.isは、引数を2つ受け取り、その2つが同じならばtrueを返すメソッド プリミティブどうしの比較にも使うことができます
object.isによる比較は最も厳密です。よって、後者と同様にnanどうしを比較するとtrueになります。 +0と-0を区別します。
もうひとつのゼロ、すなわち-0は、滅多なことでは出現しませんが、浮動小数点数まわりの演算で出現することがあります
-0は普通に-0と書くことでも(すなわち、+0にマイナス演算子を付けることでも)得ることができます +0と-0を加算すると+0ですが、-0と-0を加算した場合は-0
array#includesの場合(samevaluezero)は+0と-0は等しい
何にせよ、nanどうしが等しいような比較は今までjavascriptで使うことはできませんでした(自分で頑張って実装すれば不可能ではありませんが)。それがこのように簡単に利用できるのはありがたいですね
Object.assignです。これは、あるオブジェクトに他のオブジェクトのプロパティを全てコピーして書き込む
var obj2 = Object.assign({}, obj1);
- でコピーするのがよくなる使い方らしい
- 参照(みたいなもの)を切れるらしい
- 参照の話もここでされるらしい
ここで行われるのは浅いコピー(shallow copy)です。
- 中で参照してるオブジェクトは同じものを参照するらしい
object.assignは「オブジェクトのコピー」に利用されることが多いと思いますが、その実態はあくまでプロパティをひとつずつ新しいオブジェクトに代入しているだけです。
ES2017で追加されたObjectの静的メソッドを紹介します。それはObject.entriesとObject.valuesです。 object.valuesやobject.entriesではシンボルをキーとするプロパティは列挙できません。これは、列挙されるプロパティをobject.keysに合わせるためです
要するに、object.keysだけ仲間がいなくてかわいそうなのでentriesとvaluesを仲間に加えてあげたということです
- console.log(Object.getOwnPropertyDescriptors(obj1)); は列挙不可能でも出る
これで皆さんは正真正銘、Objectが持つ静的メソッドを全て知ったことになります。
2022/01/13 0:25 よみおわ 43m
16章はあと 5つ
全体はあと 13
十六章第十八回 ES2015とプリミティブ
https://uhyohyo.net/javascript/16_18.html 2022/01/14 22:23
- 2進数リテラルは、0bのあとに0と1を用いて数を記述します。。。console.log(0b1010);//10
- 大文字を用いて0Bとしても構いません
16進数のxは16進を表すhexadecimalの3文字目です
8進数はoctalなので、0oまたは0oとします。ゼロとオーが紛らわしいような気がしますが、小文字を使えば大丈夫でしょう。
なお、昔のjavascriptでは、頭に0oではなく0をつけることで8進数リテラルになる機能がありました。恐らく今のブラウザでも同様の動作をするはずです。この古い8進数リテラルはstrictモードでは禁止されており、文法エラー
console.log(2**3);//8 従来はMath.powメソッド
この演算子でNaNの0乗を計算すると1になります
isFiniteです。Finiteとは、Infinite(無限の)と逆で、有限ということです。この関数は数値の引数を一つとって、InfinityやNaNならfalseを返し、普通の数値ならtrue
これらの関数は、es2015ではNumberの静的メソッドとなりました。つまり、Number.isFiniteやNumber.parseIntのように使うということです。ただし、従来の関数を消してしまうと動かないコードが大量にできてしまい困るので、従来のものも使用できます。
- Number.isInteger()
ご存知の通り、javascriptの数値には整数と小数(浮動小数点数)の区別がありません
- Number.isSafeInteger
絶対値が253-1の整数ではこのようなことは起こらないのです。
Number.EPSILONには2.220446049250313e-16が入っています。これは、浮動小数点数の世界で1 + x !== xとなるような(絶対値が)最初のxです。
es2015で文字列に関して特筆すべきことは、unicodeサポートの充実です
utf-16でサロゲートペアにより表される文字(言い方を変えれば、コードポイントu+10000以上を持つ文字、あるいはutf-8で4バイトで表される文字)は、javascriptにおいて2文字として数えられる 絵文字はほとんどが4バイト文字です console.log("??".length);//2 -> 従来のjavascriptは文字の数を数えることすらまともにできなかったのです。非常に残念ですね。そこで、es2015ではu+10000以上の文字もちゃんと扱えるようなメソッドが追加されています。 それはString#codePointAt これはString#charCodeAtの4バイト文字対応版 指定した位置にある文字のコードポイントを返します ??のコードポイントはU+1F602(10進数に直すと128514)
"????"という2文字の文字列において、??のコードポイントを取得するには位置として2を指定する必要があります - String.fromCodePoint
- 複数サロゲートペアでも一文字になるとのこと
console.log(Array.from("????")); // ["??", "??"] 文字数にちょうど対応した文字の位置指定をしたい場合はこのようにイテレータ経由で配列にしてしまうとよいかもしれません -> "\u{1f602}"のようなエスケープシーケンスです。\u{ }という形の中にUnicodeコードポイントを16進数で記述することで、そのコードポイントの文字となります。従来のユニコードエスケープシーケンスは、"\u28ff"のような形でした。これも同じく\uという形を使いますが、その後ろの16進数は4桁固定です。これはコードポイントではなくコードユニットを表すエスケープシーケンスとなっているので、U+10000以上の文字を表す場合はサロゲートペアを書く必要がありました。新しい方は好きな桁数で書くことができ、コードポイントを用いて文字を表すことができるので簡単ですね。
文字列のメソッドstartsWith, endsWithは、文字列がそれぞれある文字列で始まるか、及びある文字列で終わるかどうかを判定するメソッドです。
- いままでなかったんだ?
console.log(str.startsWith("私は", 6)); // true startsWithは実質指定した位置に指定した文字列があるかどうか判定するメソッドとして利用できます、U+10000以上の文字は2文字として扱います endsWithの第2引数に数値を渡した場合は、文字列のその位置で終わるように指定した文字列があるかどうかを判定してくれます。 文字列strは"田中"の直後がちょうど10文字目
console.log("foobar".repeat(5)); // "foobarfoobarfoobarfoobarfoobar"
String#indexOfを使えば似たようなことができるのも同じですが、便利で分かりやすいので使えるときは使うとよいでしょう。 console.log("こんにちは。私は田中です。".includes("田中")); // true
normalizeメソッドは文字列を指定した方法で正規化するメソッドです。方法は第1引数で指定します。指定できるのは"NFC", "NFD", "NFKC", "NFKD"の4種類の文字列です。 正規化というのはUnicodeの概念です。
padStart, padEnd これらのメソッドは、文字列の長さが足りないときに指定した文字で埋めてしまうことができるメソッドです。padStartは文字列の先頭に、padEndは文字列の最後に文字列を付け足します。第2引数は省略することができ、その場合は" "(半角スペース)が補われます。
@@toPrimitive
オブジェクトが@@toPrimitiveメソッドを持つ場合、そのオブジェクトがプリミティブに変換される場合にそのメソッドが呼ばれます。 以前、オブジェクトがプリミティブに変換される場合に呼ばれるメソッドはtoStringやvalueOfであると説明しました。ES2015で追加された@@toPrimitiveはそれらよりも優先されます。
@@toPrimitiveメソッドが呼ばれる場合、第1引数として期待されている型が渡されます。具体的には、"string"、"number"、"default"の3種類の文字列のうちどれかが渡されます
var obj = { Symbol.toPrimitive{
- とすると、obj のこのSymbolをいじれるのだな。。
+演算子にオブジェクトが渡された場合、とりあえず指定なし(引数"default")で両辺をプリミティブに変換してみて、どちらかが文字列だったら文字列の連結になるという動作をします。
- @@toStringTag
普通のオブジェクトを文字列に変換した場合はどんな文字列になるのでしょうか。
- きになる
普通のオブジェクトは"[object Object]"という文字列になります。また、Promiseを文字列にすると"[object Promise]"となります。 このような変換結果はobject.prototype.tostringメソッドによって生成されます。このメソッドの結果は必ず"[objectなんとか]"という形になります。
- なんか違う感
console.log(String(arr)); // "foo,bar"
- 便利
読み終 2022/01/15 22:19
十六章第十九回 ES2015の正規表現
https://uhyohyo.net/javascript/16_19.html
2022/01/15 22:19 短そう 2500字
es2015の追加機能を網羅しようシリーズは今回で最後です
- たすかる 2022/01/15 22:23
実は、正規表現も従来はu+10000以上の文字を正しく扱えませんでしたが、es2015では正しく扱う方法が追加されました
ということで、今回紹介する新機能はuフラグです。uフラグを持つ正規表現は、U+10000以上の文字も1文字として扱います。
yフラグを持つ正規表現は、指定した位置からしかマッチしなくなります。位置は、正規表現オブジェクトの- lastIndexプロパティで指定します。 sticky reg.lastIndex = 3;
また、yフラグを持つ正規表現がマッチに成功したとき、lastIndexが書き換えられるという特徴があります。このときlastIndexはマッチした文字列の長さ分だけ進みます。今回の場合、文字列の3文字目から"bar"という3文字にマッチしたので、その分だけlastIndexが進み6となります。
正規表現に関連するwell-knownシンボルは4つもあります。これらのシンボルにより正規表現関連の動作をカスタマイズすることができます。
matchメソッドに、正規表現の代わりに@@matchメソッドを持つようなオブジェクトを渡すと、その@@matchメソッドが呼ばれます。他に@@replace, @@search, @@splitというメソッド これらのシンボルは正直、使いみちが全然ありませんが、万一ものすごくカスタマイズした正規表現オブジェクトを作りたくなった場合には役に立つのかもしれません。
- オブジェクトでもmatch() できるらしい
終わりみじかいい 2022/01/15 22:42
十六章第二十回 モジュール
https://uhyohyo.net/javascript/16_20.html
2022/01/15 22:43
今回は新しい文法を紹介します。それはモジュールに関する文法です。
- 確かにそういうのもあった(重要そう)
複数のファイルを協調させて動作させる仕組みが必要になります。それがモジュールシステムです。これまではどのようにjavascriptでファイル分割を行っていたのでしょうか
この例では、2つのファイルの間の協調はグローバル変数によって成されています。この例ではfoofunctionというグローバル変数が2つのファイルの間の橋渡しをしています。これまでは、事実上グローバル変数を用いるのが唯一の方法でした。
一方、近年はブラウザ以外の環境でもjavascriptが動くようになり、そういった環境用の独自のモジュールシステムが整備されてきた歴史もあります。 その代表例がnode.jsに採用されたcommonjsです。commonjsではrequireという組み込み関数を用いて他のファイルを呼び出し、結果を得ることができます。
- ◎なるほど require は nodeの commonjsの仕組み
こんかいは 9000字
// foo.js exports.fooFunction = function(){ console.log('Hi'); };
// bar.js const { fooFunction, } = require('./foo.js');
fooFunction();
モジュールのために、新しい文法import文とexport文が追加されました。import文は、他のモジュール(他のファイル)から値を読み込みます。export文は、自分が他のファイルから読みこまれるときにどんな値を提供するか宣言します。つまり、export文で提供された内容をimport文で読み込むことができるのです。
// foo.js export function fooFunction(){ console.log('Hi'); }
// bar.js import { fooFunction, } from 'foo.js';
- おなじみの記法 2022/01/15 23:26
export文にはいくつかの種類があります。
- しらんかった
- ジェネレーター関数: yield や next で段階的にすすめられるやつ
他に、var、let、constによる変数宣言にもexportを付けることができます。
- 意外に少ない 2022/01/15 23:46
export let one = 1, two = 2, three = 3;
- 全部Export
上の例のfoo、barのように、まずexport付きvarで変数を宣言しておき、あとから変数に値を代入することも可能です。この場合、他のファイルがfooやbarを読み込むとちゃんと10、20という値になります。export文を含むファイルもjavascriptプログラムであることは変わりませんので、ちゃんと上から実行されます。
- 宣言だけExportで、変更しても反映されるのだなあ
export class VeryUsefulClass{
- よくみる
export { foo, bar, };
- なるほど
また、エクスポートするときに名前を変えることができます。それには、次のようにasを使います。
export { foo as superFoo,
- はっきりとはしらなかった 2022/01/16 20:30
defaultエクスポート
- 気になる。難しかった記憶
defaultエクスポートによりエクスポートされたものは対応するimport構文により簡単にインポートすることができます
そのモジュールの中心的なものをdefaultエクスポートにするのがよいでしょう。defaultエクスポートは必ず用意する必要はありません。 変数宣言はだめです。
- 関数とクラスだけっぽい
また、好きな値をdefaultエクスポートにすることができます。
let foo=5,bar=10;。。export default foo+bar;。。こうすると15がdefaultエクスポートになります
- 宣言された後の変数はいいのかな?2022/01/16 20:42
なお、defaultエクスポートは1つしか作ることができません。
import文の基本的な形は次の形です。 import { foo, bar, } from "./foo.js";
- 普通はdefault でやるから、この形ではないのね
この例では、./foo.jsによりfooとbarがエクスポートされていれば読み込むことができます。
- エラーがデそうで安全そう
さらに、あるモジュールからエクスポートされているものを全部まとめて得るための構文もあります。
- import * as obj from "./foo.js";
- これは結構みるかも
このように* as 変数名としてインポートした場合、./foo.jsからエクスポートされているものが全てまとまったオブジェクトを得ることができます。例えば、./foo.jsからfooとbarがエクスポートされている場合、それらはobj.fooおよびobj.barに入っています。
- なるへそ
残りはdefaultエクスポートをインポートするための構文です。これは簡単です。
- import foo from "./foo.js";
- console.log(foo);
- import nanika の書き方はこのdefault のやつだけなのね
- マニアックなかきかた
import obj, { foo, bar, } from "./foo.js";
- このようにすると、defaultエクスポートがobjに入り、foo, barという名前でエクスポートされているものがfoo, barという変数にそれぞれ入ります。
他に、import obj, * as obj2 from "./foo.js";という構文も可能です。
import "./foo.js";
- これは、モジュールを読み込むけど何もインポートしないという場合に使う構文です。何もインポートしないのにモジュールを読み込む意味があるのかとお思いかもしれませんが、読みこまれると何らかの動作をするというモジュールも考えられます。そういう場合に使うとよいでしょう。
- 書き方は色々あるけょ、 defaultをつかう import hoge from "hoge.js"; が一番使うんだね
export { foo, bar, } from "./foo.js";
- これはいわゆる再エクスポートの構文です。
export * from "./foo.js";
- また、これは./foo.jsからエクスポートされているものを全て自分のモジュールからエクスポートします。ただし、defaultエクスポートは再エクスポートできません。
import文やexport文はモジュールのトップレベルでしか使えません
- モジュールってなんだっけ
モジュールとは、プログラムを分割したそれぞれの単位のこと
- export とか import したものがモジュールかな?
また、特定の条件を満たしたときだけ読み込むとかいうこともできません。もしそのようなことが必要な場合は、条件を満たさない場合は代わりにundefinedをエクスポートするなどの工夫をしましょう
実際にhtmlからこれらの構文を用いてファイルの協調を行う方法をここから見ていきますscript要素のtype属性に"module"という値を指定します。
ちなみに、モジュールでないプログラムはスクリプトと呼ぶことになっています。スクリプトでは、importやexportは使えないのです。
- モジュールとスクリプトがアンんだなあ
- moduleの中でも、普通に関数を呼べるのね 2022/01/16 23:38
諸事情により、同じディレクトリにファイルがあったとしても、"foo.js"と指定することはできない
まず、従来の方法の欠点を解説します。実は、普通のjavascriptがhtml中に現れると、それはパーサーをブロックします。パーサーをブロックするというのは、そのスクリプトの実行が終わるまでhtmlの読み込みが止まるということです。
- 普通に読み込ませてたらおそいよ ということ 2022/01/17 0:07
ただ、html5で追加されたscript要素のdefer属性を使うと、状況は少しよくなります。defer属性を付けたscript要素でスクリプトを読み込む場合、実行は後回しにしてhtmlの読み込みが続行されます そして、htmlの読み込みが終了したあとでスクリプトが実行されます なお、script要素が出た時点でファイル読み込みは開始されます。ファイル読み込みの待ち時間でhtmlの読み込みを進めることができるわけです。
src属性を持たないscript要素にdefer属性を付けることはできない
- defer がないのは即時実行なので、deferで読み込んでるものは使えない、きっと実行時エラーになる
実は、type="module"を指定されたscript要素は、deferと同様に実行が遅延されます これは、たとえsrc属性がなくても有効です。
モジュールを使うことで、deferを使うよりも自然にブロックしないスクリプトを書くことができます。これがモジュールの利点です。
- なるほど?
ファイル間のこのような階層的な依存関係を記述できるのはモジュールならではの魅力です。従来の方法では、読み込みたいファイルのscript要素を書き並べるしかありませんでした
近頃実用化が進んでいるhttp2は細かいファイルを同時に何個も受信するのが得意とされており、モジュールによるファイル分割とは相性がよくなっています
ただし、注意すべき点は、あるモジュールがどの別のモジュールに依存しているかはファイルを読み込んでみないと分からないという点です。依存関係の階層が深い場合、次々新しい依存先が発覚して結局インターネットを何往復もすることになりかねません。Server Pushを用いるなどの工夫が必要になるでしょう。
- なるほど push すれば読み込んでさっさなくていいのではやい
よみおわ 2022/01/17 0:39
十六章第二十一回 async/await
https://uhyohyo.net/javascript/16_21.html
2022/01/17 22:33
10500字
async/awaitは、またもや新しい文法機能です。これはes2017の目玉機能
このasync/awaitを理解すれば、(いくつか解説を省略している機能がありますが)es2017までのおおよそ全ての言語機能が分かったことになります
async関数とその中で使えるawait式の2つの要素から成ります async関数は非同期的な処理を記述できる関数 イメージとしては、ジェネレータ関数とyield式の関係に近い感じです
async function foo(x){ return x*10; }
async関数の返り値は必ずPromiseとなります。
foo(5) .then(v=> console.log(v));
- こうすると50と表示されるはずです。
なお、この動作は、返り値の値がPromise.resolve相当の変換によりPromiseに変換されていると見ることができます。 Promiseを返した場合はそのPromiseがそのまま返り値になります。
これだけだと返り値がpromiseに変換されるだけで面白くありません。async関数の真髄は、async関数の中でのみ使うことができる構文であるawait式にあります await式はpromiseを受け取り、そのpromiseが解決されるまで待ちます。
async function main(){ await waitFor3Seconds(); console.log('done!'); }
- 時間をかけて実行できる関数なのね
await式には任意の式を与えることができます。今回与えた式はwaitfor3seconds()です。waitfor3secondsを呼ぶと、3秒経つと解決されるpromiseを返すので、今回await式に渡されたのはそのpromiseになります。
つまり、async関数がawaitによって実行を停止している間にjavascriptは他の処理を進めることができます
main関数の実行が終了した場合それでmain関数(が行う非同期処理)が完了したと見なされるため、main関数が返したpromiseが解決されます。
promiseの結果はawaitの返り値として得る
const y = await double(x);
- Promiseチェーンで書くより見やすくなるみたい
- await と Promiseチェーンを組み合わせる場合もあるっぽい 2022/01/17 23:46
- もちろん whileを含めたりもできる
- エラー処理のまえまで 2022/01/17 23:48
エラーと関わりが深いのが例外です。そうなると、普通の処理における例外が非同期処理におけるpromiseの失敗に対応すると考えるのが自然ではないでしょうか
- まぁ、 Promise が失敗できるから、 async/await でも失敗できるらしい
async関数内で例外が発生した場合、それはその関数が返したpromiseの失敗として現れます
- async 関数がthrowすると、帰りねのPromiseの失敗としてエられるのね
- promise を async関数でカエシテもOK(そのPromiseに失敗を登録する)
await式で待っているpromiseが失敗したら、その場で例外が投げられます。つまり、await式から例外が発生したような扱いとなります
この仕組みにより、async関数を書く場合、大抵の場合はpromiseの失敗を意識する必要がなくなります
- エラーを制御するには 普通に try-catchできる
非同期処理のエラーをいい感じに処理したいという場面でも、awaitを用いて非同期処理を待つことによって、try-catchを用いて直感的にエラー処理を行うことができます。promiseの場合、catchメソッドを用いてエラー処理を行う必要があるのでどうしてもエラー処理がコールバックの中に入ることになります。
const result1 = await double(x).catch(e=> 0);
- 1行で、しかもconstでかけててすごい
このように、async/awaitを基調として使いつつ、ここぞというときにPromiseのメソッドを用いると綺麗で分かりやすいコードを書くことができます。
promiseを作る場面があるときはasync/awaitを使って綺麗に書けるか検討してみるのもよいでしょう。
async/awaitはあくまでpromise相手に動くものなので、promiseではない古い同期処理(コールバック関数とか)を相手にするのは苦手です。そのようなものをpromise化にするには生のpromiseを扱う必要がある
Promiseが増えれば増えるほどasync/awaitも便利になります。皆さんも、非同期処理は積極的にPromiseで書いていくとよいでしょう。
関数式の場合も前にasyncと書くことでasync関数を作ることができます。
// 初期値xに対してasync関数fを2回適用する関数 async function runTwice(x, f)
- 型がないからこういう書き方がデキるのね(何をかかずにfだけ)
- 関数も引数でわたせるのね
async function(x){
async x=>{
- ↑ async関数式
関数を定義する他の方法として、オブジェクトリテラル中で関数を作る省略記法があります
async func(){
- funcという名前の欠んすうなプロパてぃ
- asyncスコープいなかだけで await ということばは予約される yieldも
yomiowa 2022/01/18 23:14
ついに次タ最後 2022/01/18 23:14
2022/01/19 20:49
十六章第二十二回 TC39とJavaScriptの標準化
https://uhyohyo.net/javascript/16_22.html
短そう 4600ジ
- なんか ES2015(~2017) の新要素って、目にしたものばかりだったね
- どういうものかは知らなかったけど
Ecma InternationalのTC39は、JavaScript開発者、実装者、専門家などのグループで、JavaScriptの仕様をメンテナンスし発展させるためにコミュニティと協力しています。
- Ecmaの委員会らしい
Ecmaインターナショナル(エクマ・インターナショナル、英語: Ecma International)は情報通信システムの分野における国際的な標準化団体である。以前は欧州電子計算機工業会(英語: European Computer Manufacturers Association、ECMA)という名称であったが、世界的な展開や活動状況を反映して、1994年に現在の名称に改められた
標準化団体はいくつもあります。ECMAScriptを標準化するECMA Internationalのほかに、HTMLやDOMを標準化するWHATWGやW3C
これらの標準化団体にはgoogle、microsoft、mozillaなどのブラウザベンダが実際参画しているため、定められた標準が有効に働き、ブラウザ間での統一が成されているのです。
ECMAScriptはその番号を用いてECMA-262と呼ばれることもあります
太古の昔(1995年あたり)、はじめてjavascriptが世に登場しました。それまで動かないhtmlで書かれたページしか無かったウェブに動くページが登場するという大革命です
- IEはJScript
- 1997年には ECMAScriptになった
ここで名前がecmascriptとなったのは、当時javascriptとjscriptの2つが主に争っていたので一方の名前を付けられなかったのかもしれません。
IEを擁するMicrosoftもいつしかJScriptという看板を捨ててJavaScriptに合流したので、JavaScriptがECMAScriptに準拠した唯一の言語となり 実際に我々が書いているのはJavaScriptですが、仕様に関する文脈ではECMAScriptと呼ぶのが主流
一時期ActionScriptという言語がECMAScriptに準拠した形で作られていましたがいつのまにか別物になりました。
- ES5も確かにバージョンアップだったなあ そんなにバージョンアップ量多くなかった es5
- なんか ES2018やES2019が気になってきたぞ…
- https://qiita.com/ozoneboy/items/9c11ac3323ca94919052
- なるほど。項目だけはわかった
- やはり頼れるとほほさん
- https://www.tohoho-web.com/ex/es2020.html
- ヌル合体みたことある
- オプショナル連結(Optional Chaining)(?) も便利
インポートしたものを直接エクスポートすることが可能となりました。
- https://qiita.com/rana_kualu/items/ae3297dd2974fcf047c4
- Promise.any って ES2021からなのね
String.prototype.replaceAll これまでJSには、一致する文字列を全て置換する機能がありませんでした。 実はグローバルフラグを付けると通常のreplaceでも全置換になります。 なので、これまでも正規表現を使えば全置換は可能だったのですが、単純な文字列置換にわざわざ正規表現を持ち出したくはないですよね。
a ||= bは、aがtrueっぽい値であればそのままで、falseっぽい値であればbにする、ということになります。
JavaScriptのドラスティックな変化ってのはだいたいES2017-2018あたりでやり尽くされたかんじがあり、それ以降は"ちょっとした便利な機能の追加"ってのが多い気がしますね。
- ES2022
- https://qiita.com/rana_kualu/items/8bafecd760ae69cfac41
2022という名前にもかかわらず既に一部のブラウザで使用可能、というか一部以外のブラウザで使用可能です。
- ES2022で class に #privatemethod() ができた #y も 地味に x = 1; とかのpublic fieldも ES2022から? static も
他言語より強力な点として、リフレクションのような手段をもってしてもアクセスすることのできない完全なprivateです。
async関数の外側でawaitを使えるようになります。
export const hoge = await f(); もできるとのこと
asyncでない関数の中では相変わらず使用できません。
staticブロックは、クラスが定義された時点で実行されます。引数を渡すことはできません。
- みたことありそう
- es2023の話はまだググってもひっかからなかった
- js中級者に戻る 2022/01/19 21:19
ステージ3に上がった提案は、まだ正式にecmascriptの仕様となったわけではありませんが、徐々にブラウザ等に実装され始めます。 実際に実装してみて問題がなさそうなことを確認しないとステージ4には上がれないのです。
ステージ3の提案はほぼそのままの形で仕様となる可能性が高いですから、見ておくと予習になります
- https://github.com/tc39/proposals
皆さんはjavascript自体の言語機能はほぼ網羅してしまいましたが、domを始めとする、ウェブアプリケーションなどを作るのに必要なapiはまだ解説していないことがたくさんあります。今後はそのようなものを解説していきます。
あとはDOMだけ 2022/01/19 21:25 37m
感想
- ESは 2018以降も普通に進化していってた
- js中級者は解説の量がとてもしっかりしてたかも(解説がもっと短いものでもよかったかも)