t_hazawaの日記

株式投資とWebエンジニアリングのブログです。株式投資の目次は→です。 https://t-hazawa.hatenablog.com/entry/2021/02/12/220933

JavaScript中級者になろう 14章を読んだ (データのローカル保存)

前: JavaScript中級者になろう 13章を読んだ (通信) - t_hazawaの日記

経緯

  • JS力をつけていっている

十四章第一回 Storage

https://uhyohyo.net/javascript/14_1.html

  • cookieとの違いは、「データがサーバーへ送られるか送られないか」です storageはサーバー側からは参照できません。javascriptからのみです 基本的にはこちらのほうが便利

  • 一つはlocalStorageであり、もうひとつはsessionStorageです

  • window.localStorage, window.sessionStorage
  • localStorageは同じオリジンなら、違うページからでも同じ内容を共有できる

  • sessionStorageはタブごとにことなる 2021/12/09 0:05
  • 基本は、storageのプロパティに値を入れるとそれがそのまま保存されます。実は、保存できる値は文字列に限ります。オブジェクトとかを保存したい場合はjsonにしましょう

  • localStorage.foo="bar"; localStorage.setItem("foo","bar");

  • getItem もあるが普通にプロパティ参照でいける
  • removeItem
  • clear そのStorageのデータが全て消える
  • length
  • var key=localStorage.key(0); //0番目のキーを取得

  • window.addEventListener("storage",function(e){ },false);

  • Storageに変更があったら window に storage イベントが発生するらしい
  • ev.key ev.oldValue ev.newValue ev.url ev.storageArea
  • 大体は自分で変更したものだろうどイベントがくるんだなあ(?) ←これは違うらしい
  • 共有しているStorage (localStorage)で変更があると、他のタブでイベントがくるらしい
  • clearメソッドの場合は、key,oldvalue,newvalueが全てnullになっています。

  • コンソールで localStorage.clear() してもイベントは飛ばないようだ
  • Storageは expireしないのね (便利)
  • sessionStorage は、一度タブを閉じると1からになってしまいますね
  • sessionStorageには、一時的なデータを入れるといいね (session認証情報ではないね)

十四章第二回 Indexed Database

https://uhyohyo.net/javascript/14_2.html

  • IndexedDBだけで4回ある (使わなさそうだけど、使わなさそうなのはこれだけなのでまぁ全部読んでいいか)
  • 通称IndexedDBは、前回のStorageが進化したようなもの ある種のデータベースをjavascriptから作ってブラウザに保存しておいてもらえる

  • オブジェクト等を保存できる点や検索機能がある

  • ひとつひとつのデータはレコード(record)といい、レコードはkeyとvalueを持つ

  • データベースはオブジェクトストアを保持して、レコードはオブジェクトストアの中に保存される レコードはオブジェクトストアの中に保存されていて、1つ以上のオブジェクトストアをまとめたものがデータベース

  • データベースのなかにオブジェクトストア(MySQLのテーブルみたいなもの?)があるらしい
  • IDBRequestというオブジェクト IndexedDBに対して何か操作を行った時の結果を表すオブジェクト

  • このオブジェクトでsuccess イベントや error イベントが発生する 結果はresultプロパティに入ってる
  • この下位は 8800文字ある 前回は 4900字
  • IDBRequestのreadyStateプロパティ でも終わったかわかるぞ "pending" "done"
  • error, source, transaction プロパティもあるぞ
  • window.indexedDB でアクセス
  • windowのプロパティはグローバル変数でアクセスかのうなので indexedDB でもいける
  • open() がまずいる
  • openはデータベースを開くメソッドですが、そのデータベースが存在しない場合は作ってくれます。つまり、とにかくデータベースを使いたければopenということです。

  • 気軽なJS
  • 引数で指定したバージョンが開こうとしたデータベースより低い場合(すなわち、保存されているデータベースのバージョンが高いのにそれより低いバージョンのデータベースを要求した場合)、このアプリは新しいデータベースに対応していなくて誤動作を起こす可能性があるということなので、エラーを起こしデータベースは開けません。

  • openのバージョン番号を上げればバージョンが上がる
  • バージョン番号は省略可能(うひょさん非推奨)
  • 無事データベースを開けた場合は、IDBOpenDBRequestのresultプロパティには、IDBDatabaseのインスタンスであるオブジェクトが入っています これを用いていよいよデータベースの中身をいじることができます

  • var request = indexedDB.open("test",1); //testというデータベースをバージョン1で開く。openの返り値はIDBOpenDBRequest

  • データベースが処理中で待つ時は blocked イベントが発生する
  • データベースの名前は一度作ったら変えられない

  • close すると多分親切 しなくてもいいのかも?
  • 基本的に一つのアプリケーションなら一つのデータベースで完結するのがよいのではないでしょうか。

  • createObjectStoreの返り値は、IDBObjectStoreというオブジェクト

  • あと39回でおわり (全部で121回 2/3終わってるね)
  • versionchangeトランザクション 実はcreateObjectStoreはversionchangeトランザクション中しか使えないメソッドなので、必然的にこれを使うことになります。

  • バージョン変わるときにしかオブジェクトストアは作成できないのだ
  • versionchangeトランザクションが発動した場合、openの返り値であるIDBOpenDBRequestにおいて、upgradeneededイベントが発生します

  • このイベントの中で createObjectStore とかするらしい
  • db.createObjectStore("foo", { keyPath:"hoge", autoIncrement:true });

  • keyについては次回

十四章第三回 Indexed Database 2

https://uhyohyo.net/javascript/14_3.html

  • オブジェクトストアごとにキージェネレーターを設定できる auto increment
  • 配列、文字列、dateオブジェクト、数値(0以下の数や小数も含む) をキーに使える
  • keyというのは順番に並べることができなければいけません。これは並び替えやインデクシングなどの機能を提供するためです。

  • 異なる種類の値については、大きい方から、配列、文字列、date、数値の順になっています 文字列は文字コード順、Dateは日付順、数値は大きさ順

  • 2つの配列の、0番目、1番目、・・・どうしの要素を比較して、どちらかが大きければ、そちらの配列が大きくなります 長いほうが大きくなります。長さまで同じ場合は配列が完全に同じなので、同じ

  • key の種類が混在しててもOKらしい (フランクなJS)
  • keypathにはkeyのプロパティ名を文字列で指定します 省略すると out-of-line key になる(目に見えないどこか)

  • 自動で key になったりしないのね
  • userid も key にできて便利なのだ
  • "foo.bar"がkeyPath だと、 foo オブジェクトの中の bar がキー 。 柔軟
  • キージェネレータを使うことのメリットは、一意な連番を勝手にレコードに割り振ってくれることです

  • 結構使われるらしい
  • データベースを操作するにはまずトランザクション(transaction)を作ります read でも必要 IDBDatabaseのtransactionメソッド 返り値としてIDBTransactionオブジェクト これがトランザクションを操作するオブジェクト

  • トランザクションをつくるときにオブジェクトストアを指定しないといけないので、joinとかはなさそう
  • トランザクションを "readonly" にしてデータを守ろう というか、複数同時にデータを読めるぞ
  • "readwrite"だと順番待ちになる
  • 第2引数が省略された場合はreadonly

  • 配列を用いて複数のオブジェクトストア名を同時に指定することが可能です。この場合ひとつのトランザクションで複数のオブジェクトストアを同時に扱えます

  • joinありそう
  • abort()で強制的にtransaction失敗
  • IDBObjectStore というオブジェクトを取得してデータを読み書きしよう IDBTransactionのobjectStoreメソッド
  • versionchangeトランザクションはreadwriteトランザクションの上位互換で、データベースへの読み書きが行えるほか、オブジェクトストアを作ったり消したりすることまでできます(

  • データベースに入れることができるものの幅はけっこう広いです。 さらにdateオブジェクトや正規表現オブジェクト、fileやblob、filelist(十二章第五回)やimagedata(これはまだ解説していませんが、canvasを扱うときに出てきます)もokです

  • 以上のものを要素としてもつ配列やオブジェクトもokです

  • 入れることができないのは、関数や、nodeのようなdom関係のオブジェクトです。。。また、オブジェクトについたゲッタやセッタや、enumerableなどのプロパティの属性はコピーされず、デフォルトの状態になる

  • in-line keyの場合には、keyはオブジェクトのプロパティとなります。つまりプリミティブなどはプロパティを持てないのでレコードとしては不適で、エラーになります。

  • 配列はin-line key だとだめよ オブジェクトじゃないから
  • 逆にout-of-line keyの場合には、レコードそのものはkey情報を持たないので、レコードにこれ以上の制限はありません。

  • オブジェクトには代入してもかえられないプロパティがあるよ
  • add, putでれこーど追加
  • 第1引数が追加するレコード、第二引数がそのレコードにつけるkeyです。。。ただし、第2引数のkeyというのは、out-of-line keyのときしか使えません ii

  • キージェネレーターがアッテョ inline-key のときはkeyをレコードにするオブジェクトからしョう略デキる
  • addは重複エラー、putは上書き
  • keyとして正の数値を指定した場合で、かつその値がキージェネレータから発生する次の数値以上の場合、キージェネレータの数値が「その値より大きい最小の整数」に変更されます。

  • 便利
  • オブジェクトストアに対するひとつひとつの操作をリクエストと呼び、その結果を知らせてくれるのがidbrequestです。

  • requestへの結果だけど request
  • IDBRequest.result だからよさそう .error とかあるし
  • idbrequestではイベントが発生する可能性があります。成功したときはsuccessイベント、失敗したときはerrorイベント

  • successイベントは次の処理に進むためによく使いますし、errorイベントは、前述のように、中途半端に失敗したらトランザクションを中断して無効にするというときに、失敗の検出をするために使えます

  • addやputの場合には、idbrequestのresultは追加されたレコードのkey

  • あれもこれも request と名前つけるのはわかりにくそう。。
  • ちなみに、データベースの中身は、Chromeの場合だとDeveloper toolsのApplicationsから見ることが可能です。試しに見てみましょう。

  • あまり使われてるシーンに遭遇しないから実感がない感じ。。

十四章第四回 Indexed Database 3

https://uhyohyo.net/javascript/14_4.html

  • .get() なかったら undefined
  • .delete() resultは特にありません
  • .clear() オブジェクトストアのレコードを全部消す
  • Key Range でまとめて取得や削除ができるぞ
  • key rangeは2つの端点によって定義されます。範囲の中で最小の点と最大の点ですね。 key rangeは、IDBKeyRangeというオブジェクトで表されるのですが、作り方がほんの少し特殊

  • var range=IDBKeyRange.bound(3, 5, true, true); 開いてればtrue 閉じてれば false つまり 3< x < 5

  • 範囲の上限を指定しないkey rangeを作るには、lowerBoundメソッド upperBound only

  • さて、そうして得られたidbkeyrangeには、lower,upper,loweropen,upperopenという4つのプロパティがあります

  • このようにして作ったidbkeyrangeは、keyのかわりにgetやdeleteの引数として使えます。ただし、getにidbkeyrangeを渡しても、レコードが複数得られるわけではありません。当てはまる最初の一つのレコードのみ帰ってきます。一方deleteの場合は、当てはまるレコードを全部消去してくれます。

  • count にこのkey range を渡すとレコード数がかえってくる
  • .getAll とか .gets() みたいなのはなさそう
  • そこで登場するのがカーソル(cursor)です

  • "next" とか "prev" とか動く順番を指定できる
  • "nextunique"。nextと同じですが、重複するkeyをもつレコードは最初のものだけ見ます。。"prevunique"

  • key は重複できたんだ?
  • これは次回の話に関わってきますので、今は深く考える必要はありません。惑わされず、keyは重複しないということは覚えておいてください。

  • 奥深い Indexed DB でも、だいたいサーバにデータを保存するからあまり使われてなさそう
    • まぁ、使わなさ層のは、この講座でこのindexed db が最後だからまぁいいかな(?)
  • openCursorの返り値も、例のごとくIDBRequestです。resultプロパティの値として、カーソルを示すIDBCursorWithValueオブジェクト カーソルが現在いる位置のレコードの内容を示す、keyとvalueというプロパティを持ちます

  • advance(susumu_kazu) 戻れない

  • IDBRequst の success に通知がくるのこと
  • 最後はresult が null になるとのこよ
  • countinue(key_name) そこまですすむ
  • getAll がほしそう
  • updateです。これは、現在の位置のレコードを書き換えるというメソッド key はかえられない deleteもある

  • とても手順が大変な indexeddb

十四章第五回 Indexed Database 4

https://uhyohyo.net/javascript/14_5.html

12600文字

  • id, name, age がある場合
  • そのときには、このオブジェクトストアに対して、新たにageをkeypathとするインデックスを作ってそれを使えばいいのです 実はインデックスは自身のkeypathを持ちます インデックスは基本的に、レコードがオブジェクトでないと効果を発揮しません

  • 複数のインデックスを晴れるのね
  • versionchange トランザクションでしか新インデックスはれないよ
  • IDBObjectStoreのメソッドであるcreateIndex uniqueとmultiEntry

  • multiEntryがtrueになると、検索時の配列の挙動が変わります。配列の要素のうち、どれか一つでも条件を満たせば当てはまるようになるのです

  • deleteIndex
  • IDBIndexのgetとかでレコードを取得してね
  • 実はインデックスのkeyPathには、文字列の他に、複数のkeyPathを並べた配列も許可されています

  • もしインデックスのkeyPathが次のような配列だったとします。

  • ["party","age"]
  • このとき、このインデックスにおけるさっきのレコードのkeyは次の配列になります。
  • ["自民党",72]
  • さらに、範囲指定の例も紹介しておきます。今回の場合、政党名を1つに絞ったうえで年齢の範囲を指定することができます。

  • 範囲指定では使いにくいかもしれませんが、並び替えのためなら配列のkeypathも使い道があるかもしれません。

  • 終了してすることが何も無くなった状態を、イベントループに戻ったなどといいます。この状態になって、なおかつもう処理すべきリクエストが残っていないときが、トランザクションが終了したときです。

  • 複数のカーソルを同時に動かしたりした場合など、どちらが先に終わるのかわからないので面倒です。その場合はcompleteイベントが役に立ちます。。

  • 検索条件として範囲指定しかできませんし、複数の条件を同時に指定するのは難しいです

  • 実際には、スケールにもよりますが、とりあえずkey rangeで一次的に絞り込んで、その後は検索結果に対してif文などで絞り込んでいくことも

  • 操作がめんどそうだった

感想

  • localStorage は使いそうだった
  • IndexedIndexはとても煩雑そうで使いにくそうだった

時間まとめ

  • 2021/12/9-14
  • 10 + 44 + 30 + 30 + 32 + 14(ブログ) = 160分
  • 累計: 1601分 (= 26.7時間)

JavaScript中級者になろう 13章を読んだ (通信)

前: JavaScript中級者になろう 12章を読んだ (HTML5) - t_hazawaの日記

経緯.

  • JS力をつけてる
    • JS知識?

十三章第一回 XMLHTTPRequest

https://uhyohyo.net/javascript/13_1.html

  • 早速13000文字ある
  • Ajaxという言葉はもはや死語かもしれませんが

  • ありとあらゆるところで使われてる、ということかな?
  • Ajaxとは、AsynchronousとJavaScriptに、XMLを組み合わせて作られた造語です。

  • JavaScriptからHTTPリクエストを発行するには、XMLHttpRequestインスタンスを作ります。

  • そして、openメソッドでリクエストを開始します。このとき、パスとメソッドを渡してやります。 connectとtraceはセキュリティの観点から使えないことになっています。

  • ちなみに今回は省略していますが、第3引数は非同期フラグ(後述)で、また必要な場合、第4引数にユーザー名、第5引数にパスワードを渡すことが可能です。

  • 実はopen関数を呼ぶだけだとリクエストは送信されません。リクエストを実際に送信するのがsendメソッドです。。。sendには引数が一つあり、リクエストの本文です。

  • xhrにおいてもイベントを用います。ここで、リクエストが完了して結果が戻ってきたときのイベントはloadです。

  • onloadプロパティを設定するか、addEventListenerでイベントハンドラを登録します。

  • xhr.addEventListener("load",function(ev){ });

  • この時点で、リクエストの結果はxhrオブジェクトのresponseプロパティに入っています。

  • xhr.addEventListener("load",function(ev){ //結果を表示 document.getElementById('result').textContent = xhr.response; });

  • xhrは外で宣言してるから、このイベントリスナーの中でも使えるんだなあ
  • 結果をどんな風に受け取りたいかはXHRオブジェクトのresponseTypeプロパティに文字列を代入してやることで決定します

  • json。結果はjsonで送られてきて、それをパースした結果のオブジェクトを受け取ります。

  • arraybuffer 結果をArrayBufferで受け取ります。この方法ならばバイナリデータも受け取れます。

  • blob 結果をBlobで受け取ります。arraybufferとの違いは、Blobはtypeプロパティ(そのデータのMIMEタイプ)を持っておりこれが使用できるという点です。

  • document HTMLまたはXMLのファイルを受け取ります。結果はパースされてHTMLDocument(送られてきたHTMLファイルに対応するdocument)またはXMLDocument(XML文書の場合)で受け取ります。HTMLになるかXMLになるかは、サーバーから送られてきたデータ(のMIMEタイプ)によって自動的に判定されます。HTMLかXMLかに関わらず、この場合はresponseXMLプロパティでも結果を受け取れます。

  • 詳しくなれた
  • 上の説明でresponseTextとresponseXMLというプロパティが何気なく出現しましたが、これは昔のXHRの名残です。responseプロパティがあれば全て受け取れるので使うことはあまりないでしょうが、昔に書かれたコードに出現することがあります。

  • リクエストヘッダを設定するには、setRequestHeaderメソッドを使います。ただし、タイミングはopenメソッドのあと、sendする前でなければいけません。 xhr.setRequestHeader("Accept-Language","ja;q=0.8, en;q=0.6");

  • ただし、XHRで利用できるヘッダは制限されており、完全に自由にヘッダを操作できるわけではありません。

  • overrideMimeTypeを使ってレスポンスのMIMEタイプを書き換えることでXHRの処理を変えることができる場合があります。html なのに "text/plain" になってる場合とか

  • 次に、statusプロパティを紹介します。こちらは比較的よく使います。これは、帰ってきた結果のhttpステータスコードを数値で得ます

  • 400番台や500番台はページが見つからないなどの問題があったことを示すステータスコードですが、xhr的にはサーバーから何かしら結果が帰ってきたならば「通信成功」とみなされる

  • statusTextプロパティは、ステータスコードに対応するテキストでの説明です。これは各ステータスコードに対して定義されている文字列で、例えば200なら"OK"とか、404なら"Not Found"

  • load以外にもいろんなイベントがあるよ
  • 失敗した場合は原因によって、abort(中断)またはtimeout(タイムアウト)またはerror(その他)イベントが発生します

  • loadendイベントにおいて成功か失敗か見分ける方法としてはstatusプロパティを使う方法があります。通信成功した場合は前述の通り何らかのステータスコードが入っていますが、失敗した場合はstatusの値は0になっています。statusはまだリクエストしていない場合も0なので注意しましょう。

  • ステータスコード204 No Content
  • readystatechangeイベントについてですが、これはXHRオブジェクトのreadyStateというプロパティと関連しています。これは「現在の状態」を表す数値で、以下に列挙します。

  • 0 (UNSENT) まだopenメソッドが呼ばれていない状態。

  • 1 (OPENED) openメソッドが呼ばれたがsendメソッドは呼ばれていない状態。または、sendメソッドが呼ばれたあとまだレスポンスを受信していない状態。
  • 2 (HEADER_RECEIVED) sendが呼ばれた後、HTTPヘッダを全て受信し終えた状態。この状態からstatusプロパティやgetResponseHeaderメソッドなどが利用可能。まだデータ本体は受信していない。
  • 3 (LOADING) 本文のデータを受信中である状態。
  • 4 (DONE) 受信完了したか、リクエストに失敗して終了した状態。
  • 実は昔はこのreadystatechangeイベントしか無かったため、例えばロード完了はloadイベントではなくreadystatechangeイベントを監視してreadyStateが4になったらロード完了だと判断していました。

  • 確かに
  • 例えば。。xhr.timeout=1000;。。としたならば1秒以内に処理を完了できないとタイムアウトで失敗するということです。デフォルトの値は0で、これは無制限(タイムアウトしない)という意味になります。

  • ところで、イベントですから、イベントオブジェクトが存在します。

  • 確かに。存在感ここまでで0
  • ProgressEventという種類のイベントオブジェクト targetプロパティがありますね。この場合、targetはそのXMLHttpRequestオブジェクトになります。

  • 一つ目はloadedです。これは数値で、すでに受信した本文のバイト数です。。。次はtotalです。これは、受信すべきデータサイズの全体です。

  • totalがすでに判明しているかどうかを表すプロパティとしてlengthComputableがあります。これがtrueならば

  • progressイベントは、最短で0.05秒に1回発生することになっています

  • progressイベントと、 ev.total, ev.loaded を使うと進捗表示ができる
  • progress要素という、HTML要素がある
  • https://developer.mozilla.org/ja/docs/Web/HTML/Element/progress
  • XMLHttpRequestUploadです。これはXHRオブジェクトとセットになっていて、uploadプロパティに入っています。

  • クライアントからアップロードする部分のイベントを発生させてくれるとのこと
  • アップロードの進捗ヒョょじもできるとのこと
  • オリジンはホスト名・ポート番号・プロトコルを合わせた概念であり、これが1つでも違う2つのサイトは違うオリジンであると見なされます

  • リクエストを受ける側がhttpレスポンスヘッダによりクロスオリジンリクエストの受け入れを表明する必要があります

  • Access-Control-Allow-Origin: http://example.com http://uhyohyo.net

  • 複数許可はスペース区切り
  • ドメインを列挙する代わりに「*」とすることもできます。

  • 実はXHRオブジェクトにはwithCredentialsというプロパティがあります。これはクロスオリジンのときに関係するプロパティで、falseまたはtrue、デフォルトはfalseです。

  • trueになると何が起こるかというと、CookieとかSSL証明書などの情報も一緒に送られるようになります。これらが必要な場合はwithCredentialsをtrueにしましょう。

  • ただし、注意するのは、このwithCredentialsがtrueの状態で、さらにAccess-Control-Allow-Originが"*"でない場合(ちゃんと列挙してある場合)には、さらに追加のHTTPヘッダが必要になります。 Access-Control-Allow-Credientials: true

  • 実はopenメソッドの第3引数をfalseにすると同期的なリクエストが行われます。

  • この引数は省略するとtrue扱いになるという珍しい引数です。

  • JSではそうなんだ?
  • 現在の仕様では普通のjavascript実行環境ではxhrを同期リクエストで利用することはできません。つまり、第3引数にfalseを指定するとエラーになります。。。こんな意味のない仕様がなぜ存在するかというと、ひとつは歴史的経緯、そしてもうひとつはworkerプロセス内で利用するため

  • 同期リクエストでは、send()が呼び出された時点でブロックされ、リクエストが完了すると戻ってきます。 つまり、send()の直後にresponseプロパティを参照して結果を得ることができます。通信失敗した場合はerrorイベント等の代わりに例外が発生します。

  • バイナリデータを送りたい場合、sendの引数にArrayBufferやBlobを渡すことができます HTMLDocumentやXMLのDocumentを渡すこともできます。そうなると、そのソースを送ってくれます。

  • sendには今回初登場のFormDataオブジェクトを渡すこともできるのです。FormDataをsendに渡すと、HTMLでフォームを送信した場合と同様の本文を生成してくれます。FormDataの第一引数にHTMLFormElementを渡すとその内容を持ったFormDataが得られます。

  • teで作るのは多々変なものを作ってくれるらしい
  • var data = new FormData(); data.append("foo","bar");

  • 第2引数はBlobになります(もちろん、Blobを継承しているFileでもいいということに注意しましょう)。そして、第3引数にファイル名を与えることも可能です。すなわちこんな感じです。

  • //変数blobには何かのBlobが入っている data.append("foo",blob,"file.txt");
  • ファイルも遅れるFromData
  • ちなみに、ずいぶん長い間XMLHttpRequestがHTTP通信を発行する唯一の方法でしたが(Server-sent Eventsを除けば)、最近は新世代のfetchというAPIが登場して取って代わられようとしています。

2021/12/06 21:32 42minで読破した。

310文字/min

十三章第二回 Server-Sent Events

https://uhyohyo.net/javascript/13_2.html

5200字

  • Server-Sent Events (SSE)

  • XHRは“生”のHTTP通信を行うことができます

  • 今回のSSEはXHRに比べてハイレベルなAPIです。SSEで行うことができるHTTP通信の形は決まっていますが、より抽象化された形で通信を扱うことができます SSEを使うとpush型のデータ通信が可能になります

  • push型というのは、「サーバーから能動的にデータを送ってくる」ということです。

  • XHRでは、クライアント発しかできない pollingとか
  • サーバ発の方がリアルタイム
  • sseでは、http通信の範疇でpush型の通信を実現するために次のような方法を用います サーバーはレスポンスを送信中の状態を維持します。そして、サーバーは送りたいデータがあるたびにその接続でデータを送ります。

  • これではクライアントからデータをこの接続で送ることはできないけどね
  • サーバーはtext/event-streamというMIMEタイプでレスポンスを返します。サーバーから送られてくるデータの1単位はイベントといいます。

  • data: foo が1イベント
  • data: foo data: bar
  • これは、「foo(改行)bar」という2行の内容からなる1つのイベントです。
  • 空行くぎり
  • 送られてくるイベントデータの一行一行をフィールドといいます

  • フィールド名:フィールドの中身

  • フィールド名がdataであった場合、そのフィールドは、イベントの内容を表します。

  • event: がイベントの中身
  • イベントの名前はデフォルトである「message」

  • EventSourceというオブジェクトを使います。 var stream= new EventSource("/path/to/source");

  • eventSource.readyState 0(connecting) 1(open) 2(closed)
  • 1がイベント受信可能
  • sseの場合、サーバーからイベントを受信するたびに1回イベントが発生します。イベント名には、eventフィールドを利用して設定されたイベント名がそのまま使用されます。

  • stream.addEventListener("message",function(e){});

  • EventSource は stream という名前の変数になりがちらしい
  • 今回のイベントオブジェクトはMessageEventといいます。イベントの中身は、このdataプロパティに文字列で入っています。他にはoriginというプロパティがあり、これはイベントの配信元のURL(EventSourceの第1引数に指定したURLと同じ)が入っています

  • EventSourceはサーバーから接続が切断された場合再接続を試みる 上のreadyStateの2 (CLOSED)というのは、もう再接続もできず終了してしまったという状態

  • open や error イベントを活用しよう
  • error イベント (再接続しようとする時のイベント)で close する
  • retry:1000。data:hello
  • ミリ秒指定
  • idフィールドでイベントにidをつけられるぞ
  • 再接続時にサーバに教えると続きから送信できるように作れて便利
  • 以上でserver-sent eventsの説明は終了です。まとめると、httpでサーバー側から一方的なpush型の通信が可能だということです。あまり使い所がないかもしれませんが、もし機会があったら使うのもよいでしょう。

  • あまり使わないらしい

2021/12/07 23:57 17m

十三章第三回 Web Messaging

https://uhyohyo.net/javascript/13_3.html

4200文字 どんどん少なくなってく

  • 今回のこれはhttp通信はしません ブラウジングコンテキスト間の通信

  • ブラウザのタブ同士の通信とのこと
  • 自分で作ったブラウジングコンテキストなら知っている

  • window.openメソッドの第一引数はurlです。第二引数はウィンドウの名前です

  • 今回のサンプルはブロックされないブラウザが多いとおもいますが、これは「ボタンをクリックする」というユーザーの動作がトリガーになったせいでしょう。

  • このwindow.openの戻り値はwindowオブジェクトです。このwindowオブジェクトが、その開かれたウィンドウのブラウジングコンテキストを表すオブジェクトです

  • 今開いているページのブラウジングコンテキストに対応するのがおなじみのwindowです 開いたタブについては、そのページに対応するwindowオブジェクトを得ることができる

  • また、今まで慣れ親しんできたdocumentもwindowのプロパティです。以前述べたようにwindowのプロパティはグローバル変数として利用可能

  • 外から与えるのは「指示」だけで、実際の動作は内部で行われるようなのがいいでしょう。 操作する側のページに長々とどう変更するかのコードを送らなくてよいので

  • window.postMessage()
  • 送ることができるメッセージは、プリミティブ(文字列とか数値とか真偽値とか)や、普通のオブジェクト、配列、Dateオブジェクトなどです。また、最近よく出てくるFile, Blob, FileList, ArrayBufferも送ることができます。

  • 第2引数は送る先のオリジンです。これは、意図しないサイトに向けて情報を漏らしてしまわないように、メッセージ送る先のオリジンを指定できる この第2引数は省略できません 現在と同じ"/" 何でもOK "*"

  • メッセージを送りつけるだけなら、同一オリジンポリシーに縛られずに送ることができる

  • window.addEventListener("message",function(e){ });

  • MessageEvent
  • e.data にメッセージの中身が入ってる
  • sourceプロパティがあり、これはメッセージの送信元のブラウジングコンテキストに対応するwindowオブジェクトが入っています これを使えばメッセージを送ってきたページに対してメッセージを送り返すことができます

2021/12/08 0:12 31m

十三章第四回 Web Messaging 2

https://uhyohyo.net/javascript/13_4.html

  • 2021/12/08 22:10 0m
  • window オブジェクトで他のタブとやりとりしてると、複数の通信先タブがあると混在すん問題ッ解決する
  • そこで、通信相手ごとに専用の回線を用意して、その中で通信することができます。これがチャンネルです MessageChannel

  • チャンネルメッセージングにおいては、windowオブジェクトではなくMessagePortにおいてmessageイベントが発生します。 あるMessagePortでpostMessageメソッドを利用すると、それで発せられたメッセージはもう1つのMessagePortに届き、messageイベントが発生します。

  • MessagePortは、startとcloseというメソッド(いずれも引数無し)を持ちます

  • 普通のpostMessageでMessagePortを送って、あとはそのMessagePortで通信してね ここで、window.postMessageの第3引数が登場します。これは当然ながら省略可能であり、指定する場合は配列を渡します。配列であるという点に注意しましょう。
  • この配列の中にMessagePortを入れてやれば、向こうに届きます。受け取る側では、これはメッセージではありませんからイベントオブジェクトのdataプロパティには入っていません。window.postMessageの第3引数に渡されたものは、イベントオブジェクトのportsプロパティとして配列のまま届きます。

  • portやり取り用引数
  • なぜMessagePortは第1引数で普通に受け渡せないかというと、第1引数のデータは全てクローン(コピー)して送られるのに対し、MessagePortではクローンではなく現物をそのまま送らなければならない、という理屈からだそうです。第3引数は、現物を送るための機能ということになっていますが、今はMessagePort専用です。第3引数に渡したオブジェクトは向こうに送られてしまったので、それ以降こちら側で使うことはできません。

  • 他のオリジンのページと通信したいときに役に立つかもしれません。

読み終 2021/12/08 22:21 10m  2700文字だった 確かに 300 chars / min

感想

  • XHR以外にも2種類の通信方式を学んだ
  • 1分間で300字読んでることがわかった

時間まとめ

  • 2021/12/6-8
  • 46 + 32 + 10 + 10(ブログ) = 98分
  • 累計: 1441分(24.0時間)

JavaScript中級者になろう 12章を読んだ (HTML5)

前: JavaScript中級者になろう 11章を読んだ (ES5) - t_hazawaの日記

経緯

  • JS力が必要
  • 楽しい

第十二章 HTML5+JavaScript

十二章第一回 classList

https://uhyohyo.net/javascript/12_1.html

  • html5の策定に伴ってhtml用のdomにも新しくて便利な仕様が加えられました。

  • ここに新しいクラスbbbを追加したいならば、 myDiv.className += " bbb"としてやることでclassNameは"aaa bbb"となります。
  • classListが無い時はclass削除は正規表現とかでclassNameをなんとかしていた
  • classListはいくつかのメソッドを持ち、それらによってclass属性をいじることができます

  • ちなみに、classListは仕様上はDOMTokenListというオブジェクトのインスタンス

  • 他の属性も同じものなので、同じメソッド使えるらしい
  • element.classList.contains("long")

  • element.classList.add("foo");

  • element.classList.remove("foo");

  • 確かにこれの前は jQuery でやってたね
  • toggle
  • item とか length もある
  • getElementsByClassName() も HTML5 から
    • ES5 じゃないんだな…?

十二章第二回 フォーム

https://uhyohyo.net/javascript/12_2.html (5000字...に対して↓の文章は 2400文字ある)

  • html5になって、フォームが大きく進化しました どのように進化したかについてはぜひ調べてみましょう。

  • html5のフォームには、妥当性(validity)という概念があります。各コントロール(inputなどの入力欄)にそれぞれ妥当性があります。 フォームは、その入力内容が全て正しいときのみ送信が可能になります。

  • 全然知らなかった
  • formNode.checkValidity() // true(妥当) / false
  • reportValidityの場合、妥当でない場合はユーザーにエラーが表示されます。

  • 実は、イベントハンドラの中ではthisはevent.currentTargetと同じもの、つまりそのイベントハンドラが登録されている要素を指すことになっています。

  • input要素をはじめとするフォームコントロールはformというプロパティを持っており、これはそのコントロールが属するform要素です(なければnull)

  • reportvalidityにより表示されるエラーは「送信」ボタンを押したときのエラーと同じはずです。 reportValidityはユーザーが慣れ親しんだui(ブラウザに備え付けのui)でエラーを表示することができるため、独自のエラー表示を作るよりも分かりやすいと考えられます。

  • reportValidity は、良い感じの見た目で 入力されてませんみたいに出る(特に文言を設定しなくても出る)
  • required="" で 必須要素にできるんだね というか required だけかけばいい
  • pattern="\d{7}" で、 input type="text" の適切な入力内容を指定できる
  • 知らないことだらけ
  • onChange はフォーカスはずれないと発動しない onInput は1も時ずつ
  • HTMLの属性(pattern)だと、CSSで色を変えたりもできるとのこと
  • title要素の内容はエラーメッセージとして表示されます。

  • 多分属性かな?
  • コントロールの妥当性に関してもっと詳細な情報を取得するために、input要素等のノードにはvalidityというプロパティがあります。 ValidityStateというオブジェクトのインスタンス

  • valueMissing とかいろんなプロパティがあるので、何が悪いのか分かる
  • typeMismatch type="email",type="url"の場合に、正しい書式でない場合にtrue。

  • すごそう
  • stepMismatch 数値入力コントロールで、strep属性で指定した単位とあわない場合true。

  • なんかすごそう
  • customError 独自エラー(後述)がある場合true。 i

  • つよそう
  • JavaScript側から「妥当である」とか「妥当でない」ということを決めてやることができる コントロールのノードが持つメソッドsetCustomValidity これは、引数を1つ持ち、それはエラーメッセージです。この関数を呼び出すとエラーメッセージが設定され、その要素は妥当ではなくなります。 "" で同じメソッドを呼ぶと、妥当になる

  • form に oninput をつけると、中のどこかがinputされたらイベント発生
  • 特に reportValidity を呼ばなくても、妥当でなかったら submit でいい感じにエラー文言が出るようだ
  • たとえばtype属性が"hidden"とか、あるいは"button"とかの場合はユーザーが入力するものではないですから、妥当であるとか妥当でないとかいう概念が無いのです。 (willValidate で false)

  • input type="range" というものがある
  • これは通常、 number 入力型のようなテキスト入力ボックスではなく、スライダーやダイアルコントロールを用いて表現されます。この種のウィジェットは厳密なものではないので、コントロールの正確な値が重要でない限り、通常は使用するべきではありません。

  • type="number" というものもある
  • 。。というinput要素では、値として0,10,20,30,40,…を入力できます。このようなinput要素に対してはstepUp及びstepDownというメソッドが使用できます。引数をnとすると、n段階だけ数値を上げ/下げるメソッドです。

  • 日付入力input 要素から11 valueAsDateは、日付をDateオブジェクトで取得できるプロパティです。Dateオブジェクトはこれまで紹介していませんでしたが、昔からある組み込みオブジェクトで、日付を表すものですす。 またvalueAsNumberは、日付を1970年1月1日の0時からのミリ秒数で取得できます。

十二章第三回 History API

https://uhyohyo.net/javascript/12_3.html

  • history.back(); とかは昔からあった
  • history.forward(); history.go(3);
  • HTML5での画期的な新機能は何かというと、履歴の追加です。勝手に自分で履歴を追加できるのです。

  • ブラクラに使えそう(20年前から来た人)
  • 今のURLも変えられる
  • history.pushState(null, 'テスト', '/javascript/testtest');

  • 第2引数は 履歴のタイトルだが、現状のブラウザは対応してない
  • 第一引数 state? でオブジェクトと履歴を結び付けられるらしい
  • history.replaceState() だと、追加ではなく上書き
  • 追加した履歴を消す方法はありません。

  • SPAでは、実際にはページ異動してないのでとても大事
  • 履歴移動の検知でページを書き換える
  • popstateというイベントを用いることで履歴移動を検知することができます

  • 別のページへ行ってしまう場合は発生しません。pushStateなどによって追加された履歴の間で(すなわち、同じページの中で)履歴を移動する場合に発生してくれるイベントです

  • window.addEventListener('popstate', function(ev){ }, false);

  • 移動後の履歴に関連付けられたstateオブジェクトがイベントオブジェクトのstateプロパティに入っています。つまり今回の場合はev.stateですね

  • WAI-ARIAというアクセサビリティを向上する属性がある
  • https://developer.mozilla.org/ja/docs/Learn/Accessibility/WAI-ARIA_basics
  • history.stateを紹介します。これは「現在の履歴」に関連付けられたstateが入っています。

  • ハッシュ以降も、locationで操作できる
  • locationには、urlの各部分をいじることができるプロパティがあります ハッシュの部分だけを変更するには、location.hashを使います。例えば先程の例だと、location.hashには"#abc"と入っています。

  • ハッシュを変更してもページは変わらないがURLは変わるので同じページのままURLを返るのに使えるね
  • ハッシュを変更すると新しい履歴が追加されます 「戻る」ボタンが押されると同じページの中でハッシュだけが違うurlに移動することになります。同じページ内での履歴移動ということはpopstateイベントも発生します。

  • popstateと似たイベントとして、履歴移動のうちハッシュだけが変わった場合に発生するhashchangeイベントがあります

  • hashchangeイベントのイベントオブジェクトにはoldURLとnewURLという2つのプロパティがあり

  • hashchange イベントを使うと、openTab() みたいなのを呼ぶ箇所を減らせるとのこと
  • ハッシュを用いて履歴を管理することには、場合によってはもうひとつ大きな利点があります。それは、ページの状態とurlが対応するという点です urlからページの状態を復元可能

  • location.assign URL要素を一個ずついれられる
  • location.replace という上書き版もあるらしい
  • location.reload 更新

十二章第四回 dataset

https://uhyohyo.net/javascript/12_4.html

  • みんなだいすき data-honyarara
  • element.dataset.foo で読み書きできるよ
  • なお、属性名にハイフンが含まれていた場合キャメルケースに変換されます。つまり、例えばdata-foo-barという属性はdataset.fooBarというプロパティに対応します。

十二章第五回 File API

https://uhyohyo.net/javascript/12_5.html (10000字。↓は3500字)

  • 自由にファイルを見られてはセキュリティも何もあったものではないので、ユーザーが認めたファイルのみ見ることができるという安全仕様です。 具体的には、javascriptでどのファイルを読み込めるのかをユーザーに選択してもらう必要があります。

  • input type="file" で選択されたファイルはJSから読める
  • input要素から選択済みファイルを取得するには、このinput要素のfilesプロパティを調べます。このfilesプロパティに入っているのが、FileListオブジェクトです もしかしたら複数ファイルが選択されている可能性がある

  • length と item でいい感じに取得できる
  • filelist[0] でも取れる
  • この中に入ってるのが Fileオブジェクト
  • FileオブジェクトというのはBlobオブジェクトの一種で(つまり、FileはBlobを継承しています) Blobとは何かというとバイナリデータを表すオブジェクト、要するにファイルの中身そのものを表すオブジェクト

  • FileReaderオブジェクトで中身を取れる
  • これの特徴は非同期読み込みであるということです。JavaScriptで非同期といった場合、意味するところはコールバックで結果を得るということです。

  • async/await も今の所マだ謎の要素
  • fileReader.readAsText()
  • 同期だと プログラム側は関数の処理が終わるまで待つ このようにプログラムが待たされることをブロックするといいます

  • 今回の場合、readAsTextを「終わったら呼んでね!」と言って呼び出し

  • コールバックにイベントはニている イベントハンドラが呼ばれる
  • コールバックはだいたい1会呼び出し、 イベントは複数回ありうる
  • 1回だけ発生するイベントがコールバックであるという見方もできます。

  • var reader=new FileReader();

  • var reader=new FileReader();
  • reader.onload = function(e){
  • console.log("読み込みが終わりました");
  • };
  • reader.readAsText(file);
  • プロパティにコールバック関数を入れると、終わったときとかに読んでくれる
  • readAsTextは、第一引数にBlob(今回はFileなのでさっき読み込んだFile)を渡します。

  • 人によっては、「readAsTextが一瞬で読み込み終わったらonloadプロパティを設定する前に呼ばれてしまうかもしれない」と思うかもしれませんが、その心配をする必要はありません。詳しくは解説しませんが、これは非同期的にコールバックが呼び出される場合、必ず今まさに実行中の一連のプログラムが最後まで実行されてから呼びだされるからです。

  • 今回のプロパティonloadですが、これはどう見てもイベントloadのイベントハンドラに見えます。上で「コールバックは1回だけ呼ばれるイベントである」というようなことを述べましたが、今回はまさにそうなっています

  • イベントハンドラっぽい名前になりがちなコールバック関数設定用プロパティ
  • 実は、おなじみのaddEventListenerメソッドを使ってイベントを登録する方法もあります。

  • コールバック関数の第1引数eはイベントオブジェクト

  • コールバック関数にもイベントオブジェクトが引数で渡ってくる
  • この場合のe.targetはFileReaderオブジェクト(上の例だとreader)が入っています。

  • イベントオブジェクトe にはよく e.target がある
  • 読み込みが終わった時点で、読み込み結果はどこに入っているのかというと、FileReaderオブジェクトのresultプロパティに入っています もちろん、e.target.resultでも同じです

  • 起こることが順番に書かれないのでわかりにくいコールバック 読み終わったら起こること→読ませる の順
  • そのファイルをどんな文字コードで読み込むかは第2引数で文字列で指定します。第2引数がない場合はUTF-8になります。他に"UTF-16"とか、"Shift_JIS"などなどが使えます。

  • FileReader.readAsArrayBuffer();
  • ArrayBufferとは
  • ArrayBufferの特徴は、実際にメモリ上に連続する領域が確保されているということです。ファイルをBlobとして得られた段階では実はBlobオブジェクトが作られただけで、まだそのファイルをメモリ上に読み込んでいないかもしれません。それを実際にメモリ上に(文字列やArrayBufferの形で)読み込むのがFileReaderなのだということですね。

  • このArrayBufferというのは先々また出てくるわりと汎用的なオブジェクトなのでここで慣れ親しんでおきましょう

  • ArrayBufferはバイナリデータなのですが、実はその中身を読むにはさらに別のオブジェクトが必要なのです。面倒ですね。

  • すごくめんどくさそうな話になってきた
  • それが型つき配列(TypedArray)であり、このオブジェクトによってArrayBufferの中身をどのように(1バイトずつとか、4バイトずつとか)読むかが定まります。

  • よく使いそうなUint8Arrayから紹介しましょう。Uint8とは、「8ビットで符号なし整数」 1バイトずつ読める(8ビット=1バイトなので)

  • バイナリデータはバイト単位で区切って表示されることが多いように思いますから、これが最も自然なのではないでしょうか

  • UInt32Array (4バイト)とかある Float32Array とか TypedArray
  • var arr=new Uint8Array(buffer);

  • newで作ろう TypedArray
  • TypedArray でいじると、もとの ArrayBuffer にも反映されるよ まさにビューワー
  • ArrayBufferがメモリに確保して、そのメモリのデータをTypedArrayで操作する
  • TypedArray.length 長さ
  • ArrayBuffer.byteLength
  • arr[0]で読み書きもできるぞ
  • readAsDataURLの前まで 2021/12/01 21:10 44m
  • data: から始まるURLを読める readAsDataURL
  • DataURLというのは、データがURL内に全部書いてあり、インターネットアクセスをする代わりにURL内のデータを読むことで結果を得られるものです。

  • data:text/html,%3c%21doctype%20html%3e%3chtml%3e%3cbody%3e%3ch1%3etest%3c/h1%3e%3c/body%3e%3c/html%3e

  • ブラウザに入れると htmlとしてレンダリングされる
  • このように、ブラウザが読み込んだとき、あたかもどこかからその内容を取ってきたかのように振る舞うのがdataurlです。

  • readAsDataURL だと劇ながになることあるので URL.createObjectURL が便利
  • このメソッドにblobを引数として渡すと、オブジェクトurlと言われる特殊なurlが生成されます このurlはブラウザが発行したurlであり、そのページが閉じられるまで有効です。

  • このurlは、その内容(blob)をブラウザが覚えておき、それを指し示すものです。 データの本体はurlに書いてあるわけではなくブラウザの内部に保管されています。

  • Object URL 知らなかったなあ
  • var objurl = URL.createObjectURL(file); でつくれる

  • URL.revokeObjectURLメソッドを呼び出して(第1引数にオブジェクトURL) すると親切
  • なんかTypedArray に自分で色々データを入れてつかうことがあるらしい
  • エンディアン バイトを並べる順序のこと このせいで 2バイト以上の TypedArray は使い所が限定されるとのこと

十二章第六回 Drag and Drop API

https://uhyohyo.net/javascript/12_6.html

  • こっちも7200文字ある
  • ドラッグできる要素を作る

  • ファイルを投げ込む話しじゃなかった
  • html5のdraggable属性
  • draggable="true"
  • 単にその編の要素にかかけてもドラッグできない
  • a要素やimg要素はもともとドラッグできる

  • なるほど、あの挙動がドラッグできるということか
  • dragenterイベント
  • これは、ドラッグしながら他の要素の上にさしかかったときに発生するイベントです。

  • dragenterイベントのデフォルトアクションは「ドロップ先をbody要素に変更する」 すなわち、dragenterイベントが発生すると、どこにマウスを持って行っても全部body要素にドロップした扱いになってしまいます。

  • ですから、どこに置いてもbody要素にドロップした扱いになるのはちょっと困ります。そこで、dragenterイベントのデフォルトアクションを無効にする必要があります(これを、イベントをキャンセルするといいます) - - preventDefault - どこでpreventDefault しないといけないか知識も、JavaScript 難しさ (全部につけられれば楽そう)

  • さらに面倒なことに、実はもうひとつキャンセルすべきイベントがあります。それはdragoverイベントです

  • 驚きのめんどくささ
  • ドラッグオペレーション四種類 copy link move none
  • 実際にドロップしたときの動作はやはりJavaScriptで記述するので、ドラッグオペレーションには表示以上の意味はそんなにありません。しかし、値が"none"になっている場合はドラッグ&ドロップ自体が無効になってしまうので、何か他の値にセットする必要があります。

  • その方法ですが、dragenter,dragoverなどのDnD APIに関係するイベントでは、そのイベントオブジェクトはDragEventといい、dataTransferプロパティを持ちます。これをDataTransferオブジェクトといい、ドラッグ&ドロップに関するさまざまな情報を管理します。 - ???

  • 仕組みとしては、dragenter、dragoverなどのDnD APIに関連するイベントの場合、イベントオブジェクトはDragEventと呼ばれ、dataTransferプロパティを持っています。これはDataTransferオブジェクトと呼ばれ、ドラッグ&ドロップに関する様々な情報を管理しています。

  • //elmは適当なHTMLElementとする

  • elm.addEventListener("dragover",function(e){ e.dataTransfer.dropEffect = "copy"; e.preventDefault(); });
  • というようにすればいいらしい
  • dragoverのデフォルトアクションは「ドラッグオペレーションを"none"にする」ということなのです。

  • 確かにポインタが変わってる
  • dropイベント
  • イベントオブジェクトのtargetプロパティはドラッグ先の要素です

  • event.target は常連
  • dataTransfer には ドラッグされたもののデータを格納しておけるとのこと
  • ドラッグ&ドロップにおけるデータの流れは、「ドラッグされる側がdataTransferにデータを格納する」→「ドロップされたとき(dropイベント)にdataTransferからデータを取り出す」ということになります。

  • dragstart イベントでデータを dataTransfer オブジェクトに格納する
  • dataTransfer.setData()
  • 第一引数がフォーマットの文字列、第二引数がデータの文字列です。

  • mimeの後ろの方は x- から始まる自由文字列使える
  • この部分には"x-"から始まる自由な文字列を設定できるので、例えば"text/x-mydata"とかです。

  • dataTransferには複数のデータ から
  • 2021/12/04 23:11
  • dataTransferには複数のデータを格納することができますが、同じフォーマットのものは複数格納できません。

  • document.addEventListener("dragstart",function(ev){ ev.dataTransfer.setData("text/plain",ev.target.textContent); });

  • 同じようにaddEventListenerでイベントを付加してもいいのですが、面倒なのでondrop="drop(event)"のようにしてdropという関数を作ってそれに渡すことにしましょう。

  • イベント属性では勝手に event という引数をつけてくれるっぽい
  • function drop(ev){ var data = ev.dataTransfer.getData("text/plain"); }

  • dropイベントでも最後にpreventdefaultしているのが分かると思います。これは、(2014年7月現在)firefoxがドロップ後にページ遷移してしまうので、それを防ぐ目的があります。

  • 実は、img要素がドラッグされる場合自動的にdatatransferに画像のurl(具体的にはsrc属性の内容)が格納されます。その際のフォーマットは"text/uri-list" 複数のimg要素が同時にドラッグされている場合もあります。そのようなときは、全てのurlが改行で区切られた文字列が入っています

  • 実はa要素の場合も、そのリンク先のurl(href属性)が"text/uri-list"で入っています。

  • 実は、デフォルトでドロップ可能な要素も存在します。それはtextarea要素およびinput要素(type="text"の場合)です 実は、"text/plain"のデータがdatatransferに入った状態でこれらの要素にドロップされると、その内容が入力されます。

  • 。dragstartをキャンセルした(preventDefaultでデフォルトアプションを無効化)した場合はその要素はドラッグできません。

  • dragleaveイベント 実は、dragleaveイベントのイベントオブジェクトのrelatedTargetプロパティは移動先の要素を示しています。

  • ドラッグを続けている間、ドラッグされている要素ではdragイベントが発生し、ドラッグ先の要素ではdragoverイベントが発生します。 ブラウザにもよりますが、1秒に数回程度のペースで発生します。先に述べたようにdragoverはキャンセルしなければドロップを受け入れられません。

  • dragイベントをキャンセルした場合はドラッグが中断されます。ドラッグを強制的に止めたい場合はdragイベントをキャンセルしましょう。

  • dropeffectが"none"の場合など、ドロップが受け入れられない状況でドラッグが終了した場合はドロップ扱いにならず、dropイベントは発生しません。

  • dragendイベントがドラッグされている要素で発生します dragstart→drag→drag→……→drag→dragend dragenter→dragover→dragover→……→dragover→dragleave 最終的に要素が話された地点ではドロップ先の要素でdropイベントが発生

  • dataTransfer内のデータにアクセスできるのはdragstartイベントとdropイベント

十二章第七回 Drag and Drop API 2

https://uhyohyo.net/javascript/12_7.html

  • 4900文字
  • 実はページの外から何かがドラッグされてくるという場合もあります

  • 僕が最初考えてたDnD
  • 実は、ファイルをjavascriptから読み込む方法はもう1つあります。それが、ブラウザ内へファイルをドラッグ&ドロップしてもらうことです。

  • 言われてみればこの二種類しかないね
  • 実は、ページの外からファイルがドラッグ&ドロップされてきた場合も、ドロップ先の要素ではdragenter、dragoverその他のイベントが発生します。 実は、dataTransferはfilesというプロパティを持っており、これはFileListオブジェクトです

  • p.textContent= file.name;
    

    ev.target.appendChild(p);

  • ちなみに、紹介しそびれたdataTransferのメソッドで、clearDataというものがあります。これはフォーマット文字列を引数にとって呼び出すことで、そのフォーマットのデータをdataTransferから削除できます。

  • dataTransferを扱うメソッド(setData, getData, clearData)は実はちょっと古い方法で、最新の仕様では新しい方法が用意されています

  • なんか先に廃止サれそう
  • というか、現在(2019年7月)でもSafariというブラウザが未だに未対応となっています。そのため、以下の内容は今すぐ実用できないかもしれません。

  • 新しい方法では、DataTransfer内のデータはdataTransferが持つitemsプロパティに集約されます DataTransferItemListオブジェクト

  • この新しい方法の特徴は、addメソッドの第1引数に別の方法で生成したFileオブジェクトを渡すことでdataTransferにファイルを追加することができる

  • 古い方法では、ブラウザウィンドウの外からファイルをドラッグしてきた場合しかDnD APIでファイルを扱う機会はありませんでしたが、新しい方法ではこのようなパターンもあるのです

  • しかも、dataTransfer.items[0]のように取得したデータは生のデータではありません。ここで得られるのはDataTransferItemオブジェクトというもので、このオブジェクトからさらにデータを引き出すのが少し面倒 文字列の場合はgetAsStringメソッドで、ファイルの場合はgetAsFileで生のデータを取得します

  • 面倒そう
  • getAsStringメソッドの場合はさらに面倒です。このメソッドには引数でコールバック関数を渡す必要があり、その関数にデータが渡されます。

  • 普及しなさそう
  • 特に、この方法によって中にどのようなデータ(データのフォーマットや種類)が入っているかを知ることができます。前回dragstartイベントとdropイベント以外ではdataTransfer内のデータを見ることができないと解説しましたが、実は実際のデータを見ることはできないもののデータの種類などの情報は見ることができます。これにより、例えばdragenterイベントで、データの種類によって受け入れるかどうかを決めるというような挙動が可能になります。

  • dataTransfer.items.addとdataTransfer.setDataにはひとつ違いがあります。既に存在するタイプのデータを追加しようとしたとき、前者はエラーとなるのに対し後者は上書きします。

  • ちょっとふみそう
  • 実は、DataTransferには、setDragImageというメソッドがあり、ドラッグ中に表示する画像を設定できます。例えばdragstartでこれを呼び出すと、ドラッグ中のマウス等の画像表示を変更できる dataTransfer.setDragImage( element, x,y); elementというのは、画像として使用する要素です。一般的にはimg要素ですが、他にも任意の要素を指定可能です。x,yは数値で指定します。これは画像のつかむ場所を示す座標です。

  • ドラッグオペレーション(copy・link・move)

  • moveしかしらないような…
    • ググッテュ情報でてこなかった
  • 例えばwindowsでは、普通にドラッグすると移動(move)だけどctrlキーを押しながら移動するとコピー(copy)になります。気が利くブラウザならばそういった情報を与えてくれるでしょう。しかし、あまり期待するべきではありません。 uninitializedの場合は何をドラッグしているかによってさらに気を利かせてくれます

  • ドラッグに種類があるのね

感想

  • Form の 妥当性は全然知らなかった

時間まとめ

  • 2021/11/29 - 2021/12/5
  • 38 + 48 + 45 + 39 + 34 = 204分
  • ブログ 25分(入力システム不具合で6分つまった) 合計 229 分
  • 累計1343分 (22.4時間)

JavaScript中級者になろう 11章を読んだ (ES5)

経緯

  • 業務プロダクトをTSにする前に、JS力を高めようとなったので続き

感想

  • JSはES5 だけでなく、ES2015-2017 で段階的に強化されたのだなあ (classはES5ではなかった)

構成

11章 ES5

十一章第一回 配列 (かなりnagai、31分)

  • https://uhyohyo.net/javascript/11_1.html

  • array.lengthはarray["length"]としても参照可能 プロパティはこのような形でも三章可能 - 前にも説明あったと思う

  • プロパティ名に文字列以外が渡された場合は文字列に変換されます 数字から始まるプロパティ名の場合はarray.0のようにドットを使って参照することはできません

  • push & pop
  • pushは、配列の最後に要素を追加 popは引数がなく、最後の要素を取り除きます。取り除いた要素は戻り値となります。

  • 逆に、最初に要素を追加するメソッドもあります。それがunshiftです。一方、最初の要素を取り出すのがshiftです。

  • hairetsu.splice(1,2) 2※から2つぬき出す
  • array.splice(1,1,"小沢一郎");

  • 鳩山由紀夫小沢一郎になる
  • 4つ、5つとさらに入れるものをふやせる
  • array.reverse();
  • array.sort();
  • 引数なしなら辞書順 (コードポイント順)
    • 数値大照準ではない
  • 0未満ならaのほうがbより小さい(aのほうがbより前)、0より大きいならaのほうがbより大きい(aのほうがbより後)、0なら同じ

  • return a-b; が簡単

  • array.sort(function(a,b){return a-b});

  • 無名関数版
  • .sort() も破壊的メソっょ
  • var newarray = array1.concat(array2);

  • var newarray = array1.concat('鳩山由紀夫','菅直人');

  • 配列を文字列にする .join()
  • console.log(array.join("→")); // "麻生太郎鳩山由紀夫菅直人"

  • .slice() も非破壊的
  • 引数はspliceと違って、 slice(開始位置, 終了位置)
  • 終了位置の一つ前まで返す
  • indexOf、ないときは-1
  • 第2引数に探し始めるところがある (つかわなさそう)
  • 後ろから探す lastIndexOf()
  • ES5で登場した foreach
  • array.forEach(function(x){ var li=document.createElement("li"); li.textContent=x; ul.appendChild(li); });

  • まぁ for とあまりかわらないかな?
  • 主な利点は、カウンタ変数(for文を使ったさっきのサンプルの場合、変数i)がいらない

  • 第2引数は現在の添字、第3引数は現在処理している配列そのもの
  • mapは同じ引数が関数にくる。return すると、return した結果からなる配列を map が返す
  • JSにはメソッドチェーンがあるよ 2021/11/23 21:05 25m
  • .filter(function(){}) は、 funcが true (になるものを)返したものだけの配列を返すよ
  • every,some:配列の各要素に対する条件判定。。配列があって、「その中のどれか1つでも条件を満たせばok」とか「全て条件を満たせばok」という状況があります

  • someは、配列の要素の中でコールバック関数がtrueを返すものが1つでもあればtrueを返し、1つもなければfalseを返します

  • array.some(function(x){return x<=5;})

  • reduceです。これは関数型プログラミング言語の界隈ではfold(あるいはfold_left)と呼ばれています。

  • var sum=array.reduce(function(s,val){ return s+val; }, 0);

  • 第1引数がそれまでの計算結果、第2引数が配列の要素
  • 返り値はこの要素も含めた計算結果
  • 逆からやる reduceRightもあります。

2021/11/23 21:11 読み終 31m

十一章第二回 bind

https://uhyohyo.net/javascript/11_2.html

  • bindは九章第五回でちらっと出てきたもので、ある関数が呼ばれたときのthisの値を固定するためのメソッドです。

  • var foo = showThis.bind("菅直人");
  • function showThis で this を固定した関数を作る
  • コールバック関数の中でも外側のthisの値を使いたい場合など、thisの値を保存したい場合には役に立ちます

  • bindはthisだけでなく引数も固定できます

  • var foo = sum.bind(null,10);

  • this を null にして固定せず、最初の引数を固定してる

十一章第三回 console

https://uhyohyo.net/javascript/11_3.html

  • console.logの仲間
  • consoleという変数に入ったオブジェクトが持つlogというメソッド

  • console.debug,console.info,console.warn,console.error

  • これらは、 console.log の重要度が違う版、アイコンがかわったりする
  • 大量にログ出すときは便利かもね
  • console.dirは、「オブジェクトの場合はそのプロパティ一覧を表示する」というはとになってる
  • conosle.log の強い版 プロパティ一覧が見やすいらしい
  • console.assert 第一引数に条件、第二引数以降が今まで同様に表示するもの
  • 条件true で何もコンソールにださない
  • falseなら、第二引数以降の内容を表示しつつエラーを発生させて停止します(九章第八回で紹介したthrowと同じ感じです)

  • console.trace。。これは引数なしで、コンソールに現時点でのコールスタックを表示します

  • console.groupは、コンソールに表示されるログをグループ化します

  • console.group自体にも引数を指定することで、通常どおりログに表示させることができます。。。console.groupが呼び出された後に続くログは、そのconsole.groupのログを親としてまとめられ(グループ化)、まとめて折りたたんだりできるようになります。このグループ化は、console.groupend(引数なし)が呼び出されるまで続きます。 ちなみに、groupCollapsedというのはgroupと同じですが、最初からそのグループが閉じてまとまった状態で表示されます。

  • profileが呼ばれてからprofileEndが呼ばれるまでの、実行時間などのデータを取得できます。ちなみにprofileには引数を指定することができ、あとで結果を表示するときにそのタイトルとなります - ◎便利そう console.profile

  • console.time?console.timeEndです。これは要するにタイマーで、timeが呼ばれてからtimeEndが呼ばれるまでの時間を測定します。測定結果は、timeendのときにコンソールに出力されます

  • console.countが呼ばれるたびに数字を1増やして出力します

2021/11/25 1:14 11-3 おわり 2021/11/25 1:14 17m

十一章第四回 Objectとプロパティ

https://uhyohyo.net/javascript/11_4.html

  • ES5の特徴は、オブジェクト、特にプロパティに対する操作が強化されたことです。

  • オブジェクトリテラル
  • var obj={ foo:"bar", baz:3, };
  • 古典的な方法としてはfor-in文があります。これは以下のような形の文です。 for(var 変数名 in オブジェクト){} for(var key in obj){ console.log(key);} 左の変数に、右のオブジェクトが持っているプロパティの名前が入り、全てのプロパティについてループします console.log(obj[key]); 中身

  • 従来(ES5以前)はプロパティの一覧にアクセスする方法はこれだけでしたが、ES5においては新しい方法が用意されました。 それはObject.keysメソッドです names.forEach(function(name){ console.log(obj[name]);});

  • prototype のメソッドかどうかは ES5になってから気にすることが多くなったとのこと
  • for-in文はそのオブジェクト自身がもつプロパティだけでなくprototypeを介して参照するプロパティも列挙する

  • enumerable属性です。日本語にすると「列挙可能性」 enumerableがfalseの属性はfor-in文やObject.keysで列挙されない 属性は全部で3つあります。writable,enumerable,configurableで、いずれもtrueかfalseかです。 es5より前のjavascriptにおいてはこれらの属性は完全に内部的なもので、スクリプト側からどうこうすることはできませんでした。

  • 属性(など)をいじるには、プロパティデスクリプタを使います。これはプロパティの属性を含む諸々の情報を表すオブジェクトです。Object.getOwnPropertyDescriptor var desc = Object.getOwnPropertyDescriptor(obj, "foo"); obj["foo"] についての情報を要求 { writable: true, enumerable: true, configurable: true, value: "bar" }

  • console.log(Object.getOwnPropertyDescriptor(Object.prototype,"toString"));

  • { writable: true, enumerable: false, configurable: true, value: function toString() { [native code] } }

  • 中身はブラウザの内部処理なのでjavascriptでは表現できないといういみ

  • Object.defineProperty

  • Object.defineProperty(obj,"hoge",{ writable:false, enumerable:true, configurable:true, value:"hogehoge" });

  • configurableがfalseであるプロパティの属性はいじれません。すなわち、definePropertyしようとするとエラーになります。 writableもfalseにしておけば、もはやそのプロパティの内容は絶対に不変であることが保証されたようなもの

  • Object.prototypeのようにいじられたら大惨事になるプロパティは、いじれないようにwritableとconfigurableがfalseになっています

  • 実は、ゲッタとセッタについてもdefinePropertyを用いて設定できます

  • defineProperty で get: とか set: に関数を磯ル (正式なやり方)
  • getとsetがある場合writable属性は無視されます valueもいりません

  • 既存のプロパティに対してobject.definePropertyを使うこともできます 第三引数のオブジェクトで変えたいところだけを指定できる

  • 作成時省略された属性はfalse

  • object.defineProperties 複数プロパティを一度に作ったり変えたりする
  • Object.defineProperties(obj,{ foo:{ value: "bar", configurable:true }, bar:{ value:3, enumerable:true } });
  • 第二引数はオブジェクトで、設定したいプロパティ名をキーにしてプロパティデスクリプタを値としてもつ辞書オブジェクト

  • Object.getOwnPropertyNamesを紹介します。これは、基本はObject.keysと同じですが、enumerableがfalseのプロパティも列挙する

  • Object.hasOwnProperty() 渡した名前のプロパティが自分自身にアるか Own なので、prototypeチェーン遡らない 
  • enumerableがfalseなプロパティであっても正しく判定してくれます

  • in演算子というのがあります。これも同じようにプロパティが存在するかどうかを確かめる動作をしますが、prototypeチェーンまでさかのぼって探す console.log("attack" in zako); //true

  • このin演算子はfor-in文のinとはあまり関係ないので注意しましょう。

  • Object.propertyIsEnumerable("propertyName") // true/false
  • そもそもなかったら false

11-4 プロパティ話おわり (つづく) 2021/11/25 1:46 39m (いうほど、続く回での話は近い話ではなかった)

十一章第五回 プリミティブについて

https://uhyohyo.net/javascript/11_5.html

  • プリミティブはオブジェクト以外のもの

  • JSの世界には 数値、文字列、真偽値、undefined,null, オブジェクトの六種類のものしかない
  • hoge = "mojiretsu";
  • typeof hoge; // "string"
  • typeof では オブジェクトは "object" か "function" になる
  • typeof では null は "object" になってしまう (歴史的経緯)
  • if(typeof a=="object"&&a!=null){。} とかかく

  • プリミティブにプロパティはないが、. をつけるとString みたいなオブジェクトになる
  • プリミティブに対応したオブジェクトのインスタンスが一時的に作られる

  • nullとundefinedには対応するオブジェクトがないので変換できず、nullやundefinedのプロパティを参照しようとするとエラーになります。

  • "abc".charCodeAt(0)は97 a が 97 だから

  • "aaa".concat("bbb","ccc","ddd") // "aaabbbcccddd"

  • 配列とは異なり文字列は+で繋げられるので使う機会はやや少ないかもしれません。

  • 配列は + で繋げられないのかあ
  • "01234567890123456789".lastIndexOf("123") // 11

  • "012340123401234".indexOf("abc",2) // 6

  • 検索開始位置指定できる これも0はじまり
  • lastIndexOfの場合、前から数えた位置を渡してあげるとその位置より後ろは無視されます。

  • a.localeCompare(b)

  • aのほうがbより先なら負の値、aとbが同じなら0、aのほうがbより後なら正の値

  • 辞書順は必ずしもコードポイント順ではない
  • “n”(なんか上についてるやつ)は、コードポイントU+00F1を持ち、普通のaからzのアルファベット(U+0061?U+007A)よりずっと後ろにあります。ところが、localeCompareで比べると多くのブラウザではnはnとoの間にあるのではないかと思います。

  • localeCompareの第2引数に言語を指定することができます。言語は文字列で指定します。例えば日本語は"jp"で、英語は"en" IETF言語タグ

  • matchの場合はマッチに関する情報を配列で返して、replaceの場合は置き換え後の文字列 searchは位置番号

  • "abc123def".search(/\d/) // 3

  • "aaa,bb,c,dddd,ee".split(",") // ["aaa","bb","c","dddd","ee"]

  • "fff1ghi2jjjkkk0lmn".split(/\d/) // ["fff","ghi","jjjkkk","lmn"] - ☆なんと String.split() は正規表現もtukaeる

  • "fff1ghi2jjjkkk0lmn".split(/(\d)/) // ["fff","1","ghi","2","jjjkkk","0","lmn"] - ◎ ()でくくると、区切り文字が配列に入る

  • splitには第2引数があり、これがある場合配列の要素数の上限

  • toLowerCase, toUpperCase - 結構使うイメージ

  • "Ω".toLowerCase() // "ω"
  • "φ".toUpperCase() // "Φ"
  • "a".toUpperCase() // "A"
  • toLocaleLowerCase, toLocaleUpperCase

  • 言語に合わせて LowerとかUpperにする
  • 言語設定がトルコ語の場合のみ"I".toLocaleLowerCase()が"?"などとなります

  • ブラウザに言語設定があるので、引数でlocaleを指定しなくてもいい感じになるっぽい
  • String.trim() も便利

読み終わり 2021/11/25 19:45 33m

十一章第六回 プリミティブについて2

https://uhyohyo.net/javascript/11_6.html

  • 半壊は数値とか
  • JSはぜんぶ Number
  • Infinity NaN
  • Infinity も number
  • Number.POSITIVE_INFINITY
  • 数学的に結果が決まらないときが NaN これも number
  • console.log(typeof Number.NaN); // "number"
  • NaNを含む計算の結果が全てNaNとなる
  • 文字列から数値への変換時に、変換できない文字列はNaNになります

  • parseInt("123px") // 123

  • Number("123px") // NaN

  • parseInt("10000", 2) // 32 基数は、2から36まで可能

  • parseInt("z",36) // 35

  • zまでしか文字がないから 36進数まで
  • NaNが入ると比較は全てfalse
  • isFinite (有限か)
    • infinity や Nanでなければ true
  • nullもリテラルです。一方、実はundefinedはリテラルではなく変数ということになっています。スクリプト上にundefinedと書いた時はそれはundefinedのリテラルではなく、undefinedという値が入った変数が予め用意されているだけなのです。しかし、writable属性(十一章第四回参照)がfalseになっているので書き換えられません。

  • 正規表現リテラルもあるぞ
  • /ab+c/
  • マイナスがついたのはひとまとまりの数値リテラルではなく、単項演算子の-(マイナス)の後に数値リテラルがくっついた値であるということです。その証拠に、

  • console.log(- 100);
  • のようにマイナスを離しても動作します。
  • 単項演算子-は、簡単にいうと数値の符号を逆にして返す演算子

  • console.log(-num); // -10

    1. は 3.0 になる
  • 1e4 // 10000
  • 5.E2 // 500
  • あとは16進数
  • 0xff // 255
  • 0xDEADBEEF // 3735928559
  • console.log(num.toString(2)); // "1010"(2進法で10)
  • 基数がある Number.toString()
  • console.log(a.toLocaleString()); // "30,000"

  • 5.1.toFixed(5)//5.10000

  • 123456.789.tofixed(2)//123456.79 四捨五入

  • toExponential(小数点以下の桁数)
  • toPrecision 有効数字
  • NumberのメソッドはStringにするものばかり
  • 3.toExponential(2) は 3.0toExponential(2) になるからエラーになる
  • () とか .. にする
  • Number.MAX_VALUE 扱える数値の範囲を出してくれる MIN_VALUE
  • Boolean.prototypeには特にメソッドはありません。

2021/11/26 23:19 40m

十一章第七回 継承2

https://uhyohyo.net/javascript/11_7.html

  • 難しそう
  • ES5で可能になったよりよい継承の方法

  • ソウソウョES3では なんか複雑な prototype といろいろを書かないと行けなかった
  • console.log(Object.getPrototypeOf(zako1) === Teki.prototype); // true

  • インスタンスの側からprototypeを取得できるのは、今までに無かったES5の新しい機能です(ただし、非標準のprotoというやつはありました)。

  • インスタンスの方からprototype を取れるらしい
  • console.log(Teki.prototype.isPrototypeOf(zako1)); // true

  • instanceofとの違いは、コンストラクタに対して使うかprototypeオブジェクトに対して使うか

  • isPrototypeOf は .prototype のメソッド
  • console.log(boss instanceof Teki); // true

  • オブジェクトにつかえる instanceof
    • 全部小文字なのか…
  • 継承にかかわるのはDragonコンストラクタ内の Teki.apply(this,arguments); と、プロトタイプの Dragon.prototype = new Teki; のところでしたね。

  • あまりに直感的でないES3のけいしうょ
  • 継承したときに コンストラクタの処理がされるのが大問題
  • そこで、ES5ではこの問題を解決する方法があります。それがObject.createです

  • うーん、 classはいつできたんだっけ
  • これは第一引数にプロトタイプオブジェクトを指定すると、それをプロトタイプに持つオブジェクトを作成します。つまりこんな具合です。

  • var zako2=Object.create(Teki.prototype);
  • オブジェクトが他のコンストラクタのインスタンスであるかどうかは、オブジェクトと関連付けられたprototypeオブジェクトのみによって特徴付けられます (コンストラクタは呼ばれなくてもいいよ)

  • var zako2=Object.create(Teki.prototype);

  • Teki.call(zako2);
  • 2行目のcallは、Teki関数を、zako2をthisとして引数なしで呼べという意味ですね。コンストラクタはnewで呼ばれるときはthisの値が特別になっていたので、call(またはapply)を使ってそれを再現すればできます。

  • コンストラクタも関数なのだった
  • Dragon.prototype = Object.create(Teki.prototype);

  • のようにシンプルに継承できるらしい classがほしいね
  • Object.createに第2引数が渡された場合、インスタンスを作った後に第二引数で指定されたようにプロパティをセットして返してくれる

  • function Dragon(){ Teki.apply(this,arguments); } Dragon.prototype=Object.create(Teki.prototype,{ attack:{ configurable:true, value:function(){ console.log("ドラゴンのこうげき!!"); }, }, });

  • うーんなるほどね (classしか使わなさそうな気がしている)
  • console.log(zako.constructor === Teki); // true

  • コンストラクタを調べられる
  • 実は、関数が作られた時点で、その関数のprototype.constructorにはその関数自身が自動的に入っている状態になります。

  • なんとめんどくさいことに、 Dragon.prototype.constructor に Dragon を入れないといけない

おわり 2021/11/28 0:07 14m

十一章第八回 凍結と封印

https://uhyohyo.net/javascript/11_8.html

  • かっこいい 2021/11/28 0:22 0m
  • オブジェクトに関するいくつかのメソッド オブジェクトに対する変更を制限

  • writable属性をfalseにすれば、個々のプロパティについては書き換え不能にすることができます。しかし、新しいプロパティを追加されるような事態に対しては対応不可能

  • Object.preventExtensions(obj);

  • delete演算子によりプロパティを削除することはできます 既存のプロパティに対する操作は自由にできます

  • ◎ delete 演算子便利そう
  • Object.isExtensible() で調べられる 一度拡張不可能にされたオブジェクトは拡張可能に戻すことはできません。

  • 多分 ↑が 凍結?ちがうか 拡張不可能カ
  • Object.sealです。順番が前後しますが、これが封印ですね。このメソッドは、オブジェクトを拡張不可能にするのに加えて全てのプロパティのconfigurable属性をfalseに設定します。 writable属性は変更されません。ということは、既存のプロパティは依然として変更可能

  • なんか、実用では使わない気がしている…??
  • Object.isSealed

  • Object.freezeです。これが凍結 オブジェクトを拡張不可能にします。さらに、既存の全てのプロパティのconfigurable属性及びwritable属性をfalseにします。

  • 拡張不可能よりつよい封印よりつよい凍結
  • Object.isFrozen

おわり 2021/11/28 0:31 9m

十一章第九回 strictモード

https://uhyohyo.net/javascript/11_9.html

  • strictモードもES5から
  • 厳格モード超推進派なuhyoさん (ここまでの講座でそういう面があまり見えなかったのが不思議な感じ)
  • "use strict"; しってる
  • script タグはしらんかった
  • カンイウスコープも可能
  • function foo(){ "use strict";
  • strictモードでは、varを使わずに変数を作ることはできません。 - 知らなかった

  • グローバルスコープでvarでつくってね
  • 変数名ミスをふせげるよ
  • argumentsですが、これは実はかなり曲者なオブジェクトで、その特殊な挙動はまさに闇と呼ぶにふさわしいものです。strictモードでは、argumentsのそのような特殊な挙動がなくなります。argumentsの闇に依存してしまうといけないのでこの講座ではそういったものを紹介していませんでしたが、もし興味がある人は調べてみるとよいでしょう(しかし利用してはいけません)。

  • strictモード内ではwith文という文を使うのは禁止されています。この講座ではwith文は紹介していませんので、気になる方は調べてみましょう。。。with文を禁止することで、javascriptをより最適化することができるそうです。

  • なんか見かける気がする with
  • 使わないように使用!
  • 以外と strict モードのやってることは少なかった 2021/11/28 1:54 11m

終わり2021/11/28 1:56 13m

時間まとめ

  • 11/23 - 11/28の 6日間
    • 31 + 40 + 24 + 40 + 15 + 14 + 14 + 24 (ブログ) = 202分
    • 一回あたり 20min だ
  • 途中で 業務のTypeScript化の話をちょろっと書いた (10分)

全体の時間まとめ

  • あと残ってる回が、7 + 4 + 5 + 5 + 22 + 7 + 1 = 51 回ある 1節10分なら 510分。 実は 1日1時間なら 9日で終わる。
    • 実際には1節 20分で 1020分(17時間)では?
  • ここまでは 6 + 4 + 14 + 6 + 3 + 3 + 3 + 6 + 4 + 8 + 4 + 9 = 70 回 1節10ふんなら 700分
    • 実際には1節 20分で 1400分(23時間)では?
  • ちゃんと足してみた
    • 累計: 1114分 (= 18.6時間)
      • 一回あたり 15.9分だった
      • なので、あと 811分、 13.5時間で終わるだろう。
  • 全部で 121回。 70/121 = 58%おわった
    • 確かにマダまだ知らないことがあるね 2021/11/28 0:35 13m

JavaScript中級者になろう 10章を読んだ(XPath)

前: JavaScript中級者になろう 9章を読んだ(オブジェクト志向) - t_hazawaの日記

経緯

  • 業務システムをTypeScriptにする構想を練った
  • 息抜きがてら中級者

第十章 XPath

十章第一回 XPathとは

https://uhyohyo.net/javascript/10_1.html

  • xpathcssセレクタよりも数段強力な表現力をもちます

  • xpathには「現在のノード」という概念があります

  • 僕はこのことを認識してなかった
  • スラッシュ(/)に続けて要素名を書く構文は、子ノードへの移動を意味します

  • body要素の子に複数のp要素がある場合どれが当てはまるかというと、全部です このように、現在のノードが複数となることもあります。

  • 軸 :: ノードテスト

  • *は全ての要素ノードを意味するノードテストであり、テキストノードなどその他のノードは含みません

  • /html/body/child::text()

  • /html/body/descendant::text()と書けば、body要素内の全てのテキストノードのノードセットとなり、webページのテキストが全て集まるでしょう - ☆すごく便利そう

  • node()(全ての種類のノード)

  • /html/body//とすると、body要素を含めてそれ以下の要素全部のノードセットが結果

  • /html/body//self::p。。これは「body要素中のp要素全て」

  • /html/body/descendant-or-self:p と同じ

十章第二回 DOMでのXPathの利用

https://uhyohyo.net/javascript/10_2.html

  • XPathを実際に使ってみよう
  • documentが持つevaluateというメソッド これは、5個の引数を渡してxpathを処理してもらい、結果をxpathresultというオブジェクトで返すものです

  • 引数ooi
  • ルートノードもわたせるよ
  • 第三引数は 名前空間解決器 (かっこいい) xml よう
  • XPathResult.FIRST_ORDERED_NODE_TYPE

  • iterateNext は木構造が変わるとエラー

十章第三回 属性の取得と型

https://uhyohyo.net/javascript/10_3.html

  • /attribute:: だと、現在nodeの属性を調べるぞ
  • nodeTypeプロパティを持ち、しかもNode.ATTRIBUTE_NODEという定数で示される種類のノードであることが分かります。これが属性ノードです。なお、属性ノードの正式名称はAttrといいます。

  • 属性ノードというものがアンんだね
  • zokuseiNode.value で lang属性の値である "en" がとれる
  • attrノードが使われることは多くありません

  • xpathは文字列や数値・真偽値も扱うことができます xpathの型は真偽値型、数値型、文字列型、そしてノードセット型の4つです。

  • string(/html/attribute::lang)
  • XPathには関数がある
  • 実は属性ノードは文字列に変換すると属性の値に変換されます。

  • attribute軸を@で省略できるというものです。すなわち、 /html/attribute::lang を /html/@lang と書けます。

十章第四回 述語による絞り込み

https://uhyohyo.net/javascript/10_4.html

  • 述語(Predicates)

  • ノードテストによる絞り込みでは不十分で、もっと細かい条件を指定したい場合もあることでしょう。そういったときに使うのが述語です。

  • 述語の書き方は、/html/body/child::p[1]のように[]で囲んだ式をくっつけます

  • /html/body/p[last()]

  • /html/body/p[position()<=2]

  • /html/body/p[1]は/html/body/p[position()=1]の省略形
  • /html/body/descendant::p[attribute::lang="ja"]
  • 要素ノードなど木構造中に存在するノードを文字列に変換するときには、その子孫のテキストノードを全て連結した値になります。

  • /html/body/descendant::p[ancestor-or-self::*/@lang="ja"]
  • /html/body/p[@lang="ja"][last()]。。まず、ノードテストでbodyの子のpに絞りこまれ、次の述語でlang属性が"ja"のものに絞りこまれ、その次の述語で、絞りこまれたp要素のうち最後のp要素になります

時間まとめ

  • 2021/11/20-21
  • 15+22+18 + ブログ6分 = 61分
  • 累計 : 912分

次回

  • 次からはいよいよES2015 (楽しみ)

次: JavaScript中級者になろう 11章を読んだ (ES5) - t_hazawaの日記

JavaScript中級者になろう 9章を読んだ(オブジェクト志向)

前回:

JavaScript中級者になろう 7章・8章を読んだ - t_hazawaの日記

経緯

  • このサイトを読むのは楽しい

9章 オブジェクト志向

九章第一回 オブジェクト指向とは

九章第一回 オブジェクト指向とは — JavaScript初級者から中級者になろう — uhyohyo.net

  • プロトタイプチェーンで作られる場合(昔のやり方)と、クラスで作る場合(普通の場合)があるのが難しいポイントだなあ
  • new honyarara(); で、 honyarara 関数(コンストラクタ) を new演算子がyobidaす
  • new は新しいthis を作ってくれる 2021/11/03 17:49 10m

九章第二回 prototypeの活用

九章第二回 prototypeの活用 — JavaScript初級者から中級者になろう — uhyohyo.net

  • コンストラクタ利用、prototype 利用、 クラス利用の3種類があるのかな 多い

九章第三回 継承とは

九章第三回 継承とは — JavaScript初級者から中級者になろう — uhyohyo.net

  • function.apply()
  • function.call()
  • 前読んだけど忘れた
  • apply() this値指定カノう 引数列を配列で渡せる
    • 思い出した
  • 引数列は ES2015のspread operatorがお株を奪ったらしい
  • call は this, 引数1, 引数2,... とわたす
  • arguments を使ってても 関数の定義業は funciton sum() で、引数が内容にみえるから、 spread operator がいけてそうだね
  • newの場合は関数呼び出しの()を省略できる

  • Dragon 作りのときに、Teki の プロトタイプしか使わないので、 Teki のインスタンスをつくって、それの teki.prototype を三章する、ってことみたい(?) 2021/11/03 18:57 24m

九章第四回 プロトタイプ指向

九章第四回 プロトタイプ指向 — JavaScript初級者から中級者になろう — uhyohyo.net

  • プロトタイプ指向ではprototypeも結局のところただのオブジェクトなので、自由に操作できます。

  • 変更自由
  • Rubyのようにメタプログラミング機能が発達している言語では、クラスベースでも、結構クラスを変更できるらしい

九章第五回 クロージャ

九章第五回 クロージャ — JavaScript初級者から中級者になろう — uhyohyo.net

  • スコープのこと 2021/11/09 18:41 8m
  • グローバルスコープ以外は、関数かブロックスコープによって作られるらしい
  • なんと aaa() {} のなかで var bbb= function() {} を作れるのだ
  • 他の言語で見ない いや、無名関数ならみるけど…
  • 作った関数をグローバルに返しても、関数は生まれたスコープの範囲のものを使えるとのこと
  • クロージャは、ローカル変数に対する限定的なアクセスを提供する手段になる

  • この節からは初めて読むようだ 2021/11/09 18:55 16m
  • function MyDiv の中で無名関数を使うと、無名関数の中ではthisが無名関数のものになってしまうので、MyDivのthisには thisではアクセスできないよ (なんか parent.this みたいなのがありそうなきもする)
  • var t = this;
  • とすると、無名関数の中でも tにアクセスできるので、 t.nameにアクセスデキるようになる
  • function(e)({...}).bind(this) とすると、親のthisをfunction中にわたせる

九章第六回 ゲッタとセッタ

九章第六回 ゲッタとセッタ — JavaScript初級者から中級者になろう — uhyohyo.net

  • オブジェクトのプロパティを参照したり変更しようとするときに、関数を呼ぶというものです。このとき呼ばれる関数が、ゲッタやセッタです。
  • 単に単純に取得、変更だけのやつだけじゃないんだね 2021/11/09 19:29 27m
  • ゲッタセッタの作り方は複数あるらしい
  • get aaa(){ return 3; }, とかオブジェクトリテラルに書く
  • set aaa() {}
  • 同じプロパティの取得、設定なので、 aaa のところが同じになる
  • 必ず真偽値を返すプロパティにできたりできる
  • obj.defineGetter("a", function(){}); (めちゃ古い書き方)
  • defineProperty がナウい
  • 非標準だったので、 __で囲われている
  • 代入演算子は左を三章せず、→の価を返す
  • 無名関数によって、 _a に直接あクセスできなくするテクニック

九章第七回 プリミティブとオブジェクト(とてもnagai)

九章第七回 プリミティブとオブジェクト — JavaScript初級者から中級者になろう — uhyohyo.net

  • プリミティブも String,Number,Boolean というオブジェクトのインスタンスができる
    • プリミティブのプロパティを三章しようとしたときに
  • オブジェクトはイべてtrue
  • == で null と true になるのは null か undefined だけ
  • console.log(null==false)
  • false
  • falseはダメ 2021/11/09 19:58 47m
  • (null & defined) のグループは、これら以外の価とは==でtrueにならないとのこと。 0 や false や "" ともならないんだね
  • 真偽値とそれ以外を比べる場合、まず false が 0、trueが1に変換される
    • true == "3" は false。 true == "1" だけが true らしい
  • オブジェクトが 文字列と比較される場合、まずオブジェクトが文字列に変換される obj.toString() される
    • 数値ならvalueOf() 文字列でもtoString() が無いときに呼ばれる 逆も でも Object.prototype にあるので普通はある
  • 本来、valueOf() は数値を返すメソッドではなく、自分自身を返すメソッドらしい 2021/11/10 17:17 10m
  • オブジェクトリテラル {} とか {toString: function(){ return "3"; }}
  • 実は==(と!=)はjavascriptプログラマ達からは嫌われており、実はあまり使われていません。そもそも、勝手に型を変換してしまうというのが直感的な挙動ではありませんね。

  • === だと、もちろん null === undefined も false
  • == null だけは、よく使われるとのこと
  • 左辺が undefined または nullのときだけ trueになる
  • 特に、undefinedとnullに共通する特徴は「プロパティを参照しようとするとエラーになる」ことなので、その場合を除外したい場合などにこの比較を用います

  • わかりみ
  • 文字列連結も +
  • どちらも文字列でない場合(すなわち数値、真偽値、null、undefinedの場合)、数値の加算となり両辺が数値に変換されます。 例えば、2+trueはtrueが1に変換されるので3です。"2"+trueの場合、trueは文字列に変換されるので"2true"になります。

  • 数値以外を数値に変換する手軽な方法として、「0を引く」というものがあります。 falseも0に変換されるので、falseを引いてもいいです。

  • (number)"3" とかないの?キャスト
  • falseはわかりにくそう 
  • こうすれば、一目見ただけでは何がしたいのか分かりません。コードを汚くするのに一役かってくれます。

  • NaNは、必ず数値へ変換しなければならないのに数値への変換は不可能という困った状況をなんとかするために存在します。 数値の演算の結果を数値で表せない場合にもnanとなります(例えば0/0など)nanを含む四則演算は全てnanになります。nanを含む比較演算の結果は必ずfalseとなります。

  • nan===nanですらfalseになります。nanはプログラム上ではnanと書くと取得できます。undefinedと同様、nanという変数にnanが入っています。

  • Number.NaN の方が推奨
  • isNaN , 100.isNaN
  • String(x)
  • Number(x)
  • Boolean(x)
  • で変換できる
  • 同盟のコンストラクタと関数がある

九章第八回 例外処理

九章第八回 例外処理 — JavaScript初級者から中級者になろう — uhyohyo.net

  • throw では Error オブジェクトを投げるといいぞ。
  • err.message がある err が throw されると、コンソールが Uncaught Error: エラーが発生しました。 みたたに表示してくれる
  • new Error("message"); でもいいぞ

感想

  • クロージャの用途(tにデータをとっておく)とか知らなかったなぁ 2021/11/09 19:03 22m

時間まとめ

  • 11/3, 9, 10 に 31+48+40 = 119分 で読んだ
  • ブログは 15分ほど
  • 累計: 851分

次: JavaScript中級者になろう 10章を読んだ(XPath) - t_hazawaの日記

JavaScript中級者になろう 7章・8章を読んだ

前: JavaScript中級者になろう 5章・6章を読んだ - t_hazawaの日記

経緯

  • 業務RDSをlambda で止める資料を書いてる途中
  • 土日に社内ドキュメントシステム触るのは良くないのでJS中級者読む

第七章 さまざまな機能

七章第一回 複数のドキュメントを扱う

https://uhyohyo.net/javascript/7_1.html

  • iframe要素、すなわちインラインフレーム

  • 何の略化初めて知った
  • same origin policy オリジンが同じでないと読めないということは、例えばこのサイト上のページのjavascriptは他のオリジン(例えばhttps://google.co.jp)上のページは読めません。

  • iframeで読み込んだ文書も一つの文書だから、その文書に対応するdocumentがあります

  • iframeElement.contentDocument;

  • loadイベントをjavascriptから登録するときはwindowに登録するのがいいでしょう。

  • window.addEventListener('load', function(){
    
  • 今回loadイベントを待つ理由は、iframe要素がtest.htmlを読み込むのを待つためです

  • node.ownerDocument でどのdocumentに属してるかとれる
  • iframeの中から消えた理由は、ノードは1箇所にしか存在できないからです。既に木構造中に存在するノードが新しい場所にappendChildされた場合はこのように古い場所から移動してきます。

七章第二回 ノードどうしの位置関係を知る

https://uhyohyo.net/javascript/7_2.html

  • elem.compareDocumentPosition(anotherElem)
  • elem.DOCUMENT_POSITION_FOLLOWING
  • 4 を DOCUMENT_POSITION_FOLLOWING に変換してくれるものはないのかな (なさそう)
    • 表をみるしかないのかな
  • このように定義された順序付けを文書順とかtree orderと言います。

  • 4 + 16 で 20になることもあるよ
  • if (node.compareDocumentPosition(other) & node.DOCUMENT_POSITION_CONTAINED_BY) で、 contained_by か判定できる
  • 論理和は |
  • 排他的論理和は ^
  • ある値との排他的論理和ととった値があるとき、もう一度同じ値で排他的論理和をとると、もとの数値に戻ります。mnnとしたとき、mnn = mnn = m0 = mという性質によるものです。

  • javascriptである値を真偽値に変換するには、boolean(値)というようにboolean関数に渡せばよいです

  • 実は、a&&bの返り値はaかbかのどちらかです。具体的には、aを真偽値に変換してtrueならbを返し、falseならaを返します(aを真偽値に変換した結果を返すわけではないので注意してください) 3&&"foo"は"foo"となります。短絡実行

  • a||bはaを真偽値に変換してtrueならaを返し、falseならbを返します。短絡実行

七章第三回 条件を満たすノードを順番に処理する:TreeWalker

https://uhyohyo.net/javascript/7_3.html

  • TreeWalker
    • 初めてきいた
  • 木構造の上を移動しながら次々処理をしていく

  • document.createTreeWalker()
  • 1つめの引数は頂点ノード、2つめと3つめは条件 3つめの引数に指定するのは関数です。この関数はフィルター

  • NodeFilter.FILTER_ACCEPT, SKIP, REJECT
  • tw.previousNode,nextNode
  • var node; while( node = tw.nextNode() ){ node; //そのノードに対する何らかの処理 }

  • parentNode() は条件を満たす親、祖先ノードに移動します(近い方から順にためす)

  • previousSibling,nextSibling 兄弟ノード

七章第四回 ノードをまとめて扱う:DocumentFragment

https://uhyohyo.net/javascript/7_4.html

  • documentfragmentというものです。これは、題名の通り、複数のノードをまとめて扱うのに必要なものです。 これはノードの一種です 小型のdocumentのようなもの - 全く知らなかった

  • 3兄弟を抜き出した時の親がDocumentFragment 仮の親
  • document.createDocumentFragment();
  • DocumentFragmentを追加した場合、DocumentFragment自体は追加されず、DocumentFragmentの子ノードが直接追加される

  • documentfragmentに先にまとめて追加しておき(documentfragmentはdocumentとは独立した木構造だから追加しても画面を書き直す必要がありません)、最後にdocumentfragmentを追加すればいいのです。

  • 1つ1つ、ほんもののdocument にノードを追加するより、ブラウザ的に楽らしい 2021/10/30 15:58
    • なんか重要そう
  • HTML5ではtemplate要素の中身がDocumentFragmentにより表されています

七章第五回 サンプル:見出しのリスト

https://uhyohyo.net/javascript/7_5.html

  • .textContent
  • また、textContentプロパティに文字列を代入することができ、その場合その要素の子がテキストノード1つになります

七章第六回 サンプルの改良

https://uhyohyo.net/javascript/7_6.html

第八章 Range

八章第一回 Rangeとは

https://uhyohyo.net/javascript/8_1.html

  • また知らないものがきた
  • 『え』から『お』まで

  • ノードにまたがった範囲を表せるらしい 2021/10/30 17:03
  • オフセットは数値です。これは、最初の子ノードの前を0として、その次を1,その次を2,・・・と順番に番号をつけていったものです。

  • テキストノードだと、オフセットがどの文字の間か、テキストノード以外では、オフセットがどの子ノードの間かになるみたいだ(?)
  • document.createRange();
  • この Range を何に使うのかはこの後書いてあるのだろう

八章第二回 Rangeの機能

https://uhyohyo.net/javascript/8_2.html

  • range.deleteContents() 削除できる
  • range.cloneContents()
  • 親は DocumentFragments
  • range.extractContents() とってこれる
  • range.compareBoundaryPoints()
  • node.compareDocumentPosition()
  • range.toString() は、Rangeの範囲を全てテキストにして返すメソッドです。

八章第三回 Rangeの活用とSelection

https://uhyohyo.net/javascript/8_3.html

  • selection というものはよく使うらしい ユーザーが選択した範囲を表すものです。
  • window.getSelection()
  • selection.getRangeAt(0);
  • 最初のRangeを取る
  • SelectionからRangeを除去する機能です。選択部分をSelectionから除去すると、実際に選択が解除されます。

  • selection.removeAllRanges()
  • document.addEventListener('selectionchange',function(ev){
  • range.surroundContents(newParentNode)
  • 新しいおやをいれてかこわせる

八章第四回 サンプルの改良

https://uhyohyo.net/javascript/8_4.html

  • range.compareBoundaryPoints() を活用してる
  • テキストノードにスタイルをつけるにはいちいち spanで囲わないといけなくて不便
  • range.startContainer.splitText(range.startOffset); テキストノードの分割方法
  • node.nodeType, TEXT_NODE, ELEMENT_NODE
  • textNode.splitText(3) テキストノードをわける
    • 返り値は、後ろに作られた新しいテキストノードです。

感想

  • 知らないことをしれてよかった
    • DocumentFragment は大事そう
  • なんかあんまり使わない機能のような気がしなくもない (後半の「新しいJS」の章に期待)

時間まとめ

  • 2021/10/23 に始める
    • 10/23, 24, 30(2回), 11/1 にやった 5日分
    • 120分程度(ブログ以外)
      • 1章1時間程度
    • ブログは15分くらいかな
  • 累計: 717分

次: JavaScript中級者になろう 9章を読んだ(オブジェクト志向) - t_hazawaの日記