カメリアの記事

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

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 () {}
  .
  .
  .

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

JavaScript で element.style.width = element.getBoundingClientRect().width が効かない

element.style.width = element.getBoundingClientRect().width

効かないんです。下のような場合は効くのですが。

element.style.width = window.innerWidth

だから誤解していたんです。あれが足りないことに気付かなかった。

element.style.width = element.getBoundingClientRect().width + "px"

たったこれだけでした。

JavaScript で括弧を開く(括弧内で改行する)のが僕の昨今の流行り

一般的にどうなのか知らないのですが、なんでも括弧を開くのが僕の最近の流行りです。下のようにします。

something.push(
  // 処理
)

resolve(
  // 処理
)

if (
  a === 0
  &&
  b !== 0
) {}

上の二つなんかは変数に代入しないから二度手間にならなくていいかなぁ、と思っています。下の if のやつは別の記事「条件式の書き方の提案」で話を出したことがあります。一般的に使われている手法なのか知らないのですが、複雑な条件式も理解しやすくなります。

僕としては console.log() も開きたくなります。下のように書きたいのです。

console.log(() => {
  return true
})

出力されるのは下のとおりです。

() => {
  return true
}

そのまま返されてしまいました。コマンドの echo みたいですね。くそう。