カメリアの記事

意味があることやないことを綴ります

JavaScript の module で JSON を読み込んでみた

fetch するのは大げさだな、という気がしていたのです。内部的にどうなっているのか知りませんが、 module で読み込めたら素敵だと思いした。早速「 JSON Modules が使えるようになった」を参考に下のようにやってみました。

import test from "./test.json" assert {type: "json"}

相対パスで指定して「 ./ 」の明示は必須のようです。そうしたら――

Uncaught SyntaxError: Cannot use import statement outside a module

――「モジュールの外部で import ステートメントを使用することはできません」あれ? 2 時間悩んだのですが、見落としでした。見落としていたのは下の部分です。

<script type="module">

module であることを HTML で宣言しないといけないんですね。

で、このときはスクリプトを HTML 内に書くつもりだったのでこれでよかったんですが、気が変わって別ファイルにすることにしました。それでまた同じ問題が発生したのです。え、書いているコードが module であることをどうやって宣言するんでしょう。さらに 1 時間悩んで得た答えが下です。

<script src="test.js" type="module"></script>

ダサっ。いちいち HTML で宣言しないと module になれないみたいです。自分だけで完結しないなんて。そんなの fetch するほうがよっぽどいいじゃないですか。なんだこれ? 僕は何か見落としているのでしょうか。サーバサイドで書くときはまた違ってくるのかなぁ。今回 import は使わないことにしました。

Promise.all() は Promise の配列ならなんでもいいっぽい

以前「 for 文で Promise.all() 」という記事を書いたんですが、いろいろやってみると Promise.all() としては Promise の配列ならなんでもいいっぽいです。下のようなものも可です。

Promise.all(
  array.map(rly => fetch(rly))
)
.then(rly => {
  // 処理
})

上述は map() を例にしていますが forEath() でもよさそうですし。

JavaScript の即時関数ってなんだ

即時関数という語を知りました。なんだそれ。とりあえずググって「即時関数の使い方と構造について」という記事を流し読み。ざっくり「即時実行される関数の書き方」というような印象。下のような書き方になります。

(function() {
  // 処理
})()

ショートハンドで下のようにも書けます。

(() => {
  // 処理
})()

ここまで来るとどこかで見たような記述です。下のような場合です。

window.addEventListener("click", () => {
  // 処理
})

構造上、メソッド addEventLinstener() に引数 "click" が渡されていますが、そこんところをスルーして書くと下のようになります。

(() => {
  // 処理
})

なんだあれと同じかぁ、と思ったわけですが、これじゃ実行されない! そう、前の記述では addEventListener() が実行してくれていたわけですが、この記述では実行してくれる人がいないのです。

そもそも即時関数のお尻の () ってなんだ。こいつが実行しているのか。実際この括弧を付けると実行されます。そういえばお尻に括弧というと下のような記述で重要な役割を果たします。

let something = () => {
  // 処理
}

これで下のようにするとエラーは出ませんが実行もされません。

let something = () => {
  // 処理
}
something

そう、ここで括弧の出番です。括弧を付けると実行されるのです。

let something = () => {
  // 処理
}
something()

お尻の括弧が実行していた! ということは……?

let something = function() {
  // 処理
}()

おお、これだと実行されますね。ただちょっと不可解なことがあって下のようにショートハンドで書くとエラーが出るということです。

let something = () => {
  // 処理
}()

うーん、よく分からない。教えて偉い人。だけど関数本体を括弧でくくると正常に動作します。下のような感じです。

let something = (() => {
  // 処理
})()

どうも関数本体をくくった括弧には何か意味があるようです。詳しい人ならきっと知っているでしょう。括弧はなんだか意味深ですからね。この話はここまでにしましょう。だって分からないんだもん。

さて、こうなってくると普通の即時関数と変わらない様相を呈してきました。 let something なんていらないんです。

(() => {
  // 処理
})()

そういうわけで関数名のお尻に付けるのと同じような括弧なんですが、関数と同じように引数を与えることができるようです。

((a, b) => {
  console.log(a + b)
})(1, 2)

へぇ。なんか普通の関数と何が違うんだよ、という気がしてきます。冒頭で紹介した記事「即時関数の使い方と構造について」ではグローバル変数に影響を与えずに書けるのがすげぇんだよ、という話だったのですが、それは普通の関数も同じです。そんな「即時関数」なんて特別に名前を与えるほどの意味があるんでしょうか。僕としては下のような記述のショートハンドという感覚で受け止めています。

something()
function something() {
  // 処理
}

でも僕より次元の違う頭脳を持った ECMA の皆さんが考え出した方法ですからもっと深い意味があるのでしょう。その JavaScript の深淵を探るために僕は初めて JavaScript の書籍を購入しました。

深淵をのぞくとき、深淵もまたあなたをのぞいているのだ。

さて、僕自身が JavaScript にならないよう注意しながら読んでみることにします。

JavaScript で同じ文字列の繰り返しから 1 個減らす処理 ――正規表現は奥が深かった――

複数の改行から 1 個減らす処理というのを書いたことがあるのですが、下のようにしていました。

src.replace(/(\r?\n)+/g, rly => {
  rly.replace(/\r?\n/, "")
})

ついさっき気付いたのですが、もっと簡単に書くことができます。

src.replace(/\r?\n((\r?\n)*)/g, "$1")

なんてことでしょう! 気付いてしまうと、気付かなかったかつての自分が哀れに見えます。正規表現は奥が深いですね。

JavaScript で if 文を並べると

いろんな条件でいろんな処理をさせようと下のように書いたことがあります。

if () {}
if () {}
if () {}
  .
  .
  .

条件文がしっかりしていれば全ての if 文が同時的に走って処理が速くなりそうだし、いいかなーと。でも条件文が悪かったのかもしれませんが、上手く動作しません。 if の実行文には Promise の resolve() がそれぞれ含まれているんですが、正常に resolve() されなくて。結局 else if を使って下のように書きました。

if () {}
else if () {}
else if () {}
  .
  .
  .

これだと正常に動作します。「解せぬ」という感じなんですが、確実に条件分岐できる条件文を書いて実験してみるのも面倒でほったらかしです。もしも実験したならレポートするつもりなんですが、僕の遭遇した不正常な状態が再現されれば原因の究明もできようというものでしょうけど、正常にしか動作しなかったら、やっぱり僕が間違っていたのか条件が違って発生しないのか、謎が残ります。あまり気の進む話ではないですね。