Panda Noir

JavaScript の限界を究めるブログでした。最近はいろんな分野を幅広めに書いてます。

JavaScript

forEachの使い方1選

forEachって要らなくない?と思ってたんだけど使い道あるなと気づいたので紹介 nullableなリストに対してループしたい時に使える nullableList?.forEach(item => {}) これはfor-ofで書こうと思うとちょっとダルい if(nullableList != null) for (const item o…

useRefの初期値を1回だけ計算したい

useStateは初期値に関数を受け取ると、その関数を初期化時に呼び出してそれ以降は初期化処理を行いません。 const [todos, setTodos] = useState(createInitialTodos); // 初期化コストが高い 対してuseRefは関数を受け取って初期化するという機能がありませ…

dom-testing-libraryはブラウザ環境でも動く

「getByRoleをブラウザ環境でも使えると嬉しいな〜」と思ってたんですが、普通にdom-testing-libraryはブラウザ環境でも動かせる(実DOM APIと互換がある)みたいです。 import { useEffect } from 'react'; import { screen } from '@testing-library/dom'; e…

listboxをアクセシブルに実装したい

listbox というUIパターンを実装しました。ちょっと凝ったラジオボタンリストみたいなものです↓ 仕様 クリック時の挙動はだいたいラジオボタンと同じです。 キーボード操作時がラジオボタンと違っています。ラジオボタンではフォーカス移動と同時に選択が行…

ターミナルでspinnerを表示する

デモ これを実現するためのshowSpinner関数を作りました。 function showSpinner() { const spinnerFrames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]; let spinnerIndex = 0; const spinner = setInterval(() => { process.stdout.write(`\r\x1…

エフェクトイベント関数はuseEffectのdepsに"入れてはならない"

depsに入れなくて良い、ではなく、入れてはならない です。 エフェクトイベント関数をdepsに入れるとレンダリング毎にエフェクトが走る useEffectEventは レンダリングごとに新しい関数を返します (検証用デモ)。 そのため、useEffect の deps にエフェクト…

【考察】use APIの内部構造を予想してみた

※この記事はuse APIへの自分の理解と、実際にコードを起こして実験した結果を記しただけの 考察記事 です。正しさは保証されていません。「多分こういうマインドセットを持ってるとええんやな〜」くらいの温度感でお楽しみください。 導入: Throw a Promise…

memoized関数を??=で簡潔に書く

引数が1つもない関数のメモ化をするとき、??=を使うと簡潔に書くことができます。 let cache = null const memoizedFun = () => { return cache ??= fun(); }; initializeSdk とかそういう全体で1回だけ呼び出せば良くて、初回呼び出しのPromiseを使い回した…

zennの記事をlikes数でソートする

container.appendChild(article));})();">like数順でソート ← この保存用リンクをブックマークバーにドラッグ&ドロップするとすぐ保存できます。 実際の中身はこんな感じです↓ javascript:(function(){ const articles = [...document.querySelectorAll('art…

ローカルのgigetテンプレートをテストするためのサーバーを作った

gigetはまだfile:///をサポートしてないので、作ったテンプレートを試したかったらアップロードするしかない。そこで、ローカルにtarballを返すサーバーを立てるようにした。その紹介の記事。 github.com 使い方 サーバーを起動する node server.js {テンプ…

rowspanを考慮してtable要素を2次元配列に変換する(第一正規化する)

rowspan、colspanがあるとtd:nth-of-type などがズレてしまう。 td:nth-of-type(2) に背景色をつけた図 html <table> <tr> <td>col1,1</td> <td rowspan="3">col1,2</td> <td>col1,3</td> </tr> <tr> <td>col2,1</td> <td>col2,2</td> </tr> <tr> <td>col3,1</td> <td>col3,2</td> </tr> <tr> <td>col4,1</td> <td>col4,2</td> <td>col4,3</td> </tr></table>

機能別のECMAバージョン対応表

ある機能がどのECMAバージョンで入ったのかの一覧表。ある程度グルーピングをしてある。 2025年現在のproposalsのfinished-proposals.mdを参照している。 (なお、全部確認はしたはずだが、間違ってる可能性もある。抜け等あったらコメントお願いします) Arra…

素数を判定する正規表現を紹介: /^.?$|^(..+?)\1+$/

先日、正規表現のネタをツイートしたら軽く拡散しました。そこで他にも面白いものあるのかなと調べてみたら素数を判定する正規表現があるという記述を見つけました。 これが実際の正規表現を使った素数判定です↓ const isPrime = (n:number) => !/^.?$|^(..+…

useEffectにはコメントをつけよう

「なにをしたいuseEffectか」をコメントしておくと、後で読むときのコストが下がりやすい。 実際にプロダクトコードで書いたことがあるコメント↓ (簡略化してます) // 画面内に入った動画を自動再生する+ほかの動画は停止する (すでに再生済みだったら再生し…

spread演算子を使うときに {} と {foo:undefined} は挙動が異なる

const obj1 = { foo: 42, ...({ foo: undefined }), }; // {foo: undefined} const obj2 = { foo: 42, ...({}), }; // {foo: 42} ↑こんな感じで、undefinedが指定されているときとプロパティ自体がないときでは動作が異なります。 (実は上のコードはそのまま…

逆FizzBuzzを解いてみた2

全然書いた記憶はなかったんですが、昔の僕は逆FizzBuzz という問題に挑戦してました。 逆FizzBuzzを解いてみた - Panda Noir この解答コードがもうちょいシンプルに書けたので載せておきます おさらい: 逆FizzBuzzとは? [1,2,3,4,5,…] のように並んだ数列が…

pubsub パターンの現時点でのベストプラクティス

以前pubsub パターンのベタープラクティスを考えたんですが、よく考えたらイベント名を設定する必要なかったです。 これでよさそう↓ class PubSub<Payload extends unknown[]> { private listeners: ((...payload: Payload) => void)[] = []; subscribe(callback: (...payload: Payload)</payload>…

ワンライナーでバージョン文字列を比較する

結論: localeCompare を使う a.localeCompare(b, undefined, {numeric: true, sensitivity: 'base'}) 参考: https://stackoverflow.com/a/65687141 localeCompare は IE11 でも使えるので、使えない心配はほぼありません。 しかし、locale とついているため…

循環参照がある配列で flat を呼び出すとどんどん長くなる

何に使えるかは全然わからないですが発見したのでメモ。 まず循環参照を持った配列を定義します。 const a = []; a[0] = a; a[1] = 0; これの flat を呼ぶと面白いことが起きます。 console.log(a.flat()); // [ <ref *1> [ [Circular *1], 0 ], 0, 0 ] console.log(</ref>…

オプショナルチェーン演算子は短絡評価される

const fun = () => {}; fun?.(console.log('hoge')); ↑この時は console.log('hoge') が評価され、ログに hoge と表示される。 const notFun = undefined; notFun?.(console.log('hoge')); ↑この時 console.log('hoge') は評価されない。つまりログにも hoge…

関数はアロー関数と function どちらで書くべきなのか?

結論: (トップレベルで関数を宣言するときに限り)function かアロー関数かは好みの問題。 アロー関数が出てきた当初と状況が変わってきた www.pandanoir.info 2016年に「function よりアロー関数を使うべき(function は適切な場面でのみ使うべき)」という記…

LSP のファイル名変更機能を使った mv コマンドを実装した

タイトルのとおりです。 作ったもの tsserver には、ファイルを移動させると相対パスを自動で修正する機能があります。 例えば A.tsx を B.tsx にリネームすると、A.tsx を import していた箇所が自動で修正されます。 import {Component} from './component…

@testing-library/react の debug が途中で途切れてしまう問題について

debug の出力には文字数制限があります。それを回避する方法について紹介します。 in short: debug ではなく prettyDOM(baseElement)) を使う const { debug } = render(<HelloWorld />); debug(); ↓ import { prettyDOM } from '@testing-library/react'; const { baseEle</helloworld>…

data-attributes に色々渡してみる

const Component = () => <div data-foo={xxx} /> みたいに色々な値を data-attribute に渡してみました。 結果: undefined, null: そもそも追加されない NaN: ワーニングが出る そのほか: 文字列に変換されて値としてセットされる 検証に使ったデモがこちら</div>

JSON.stringify の返り値は undefined になることがあるよ

JSON.stringify(undefined) は undefined です。 以上です。 JSON.stringify(undefined) の結果は?— panda noir (@le_panda_noir) 2022年1月20日 正答率10%。みんな undefined を渡したときの挙動を知らなかったっぽいですね(僕も知りませんでした) 補足 JS…

Jest モック方法まとめ

追記: 本記事は誤っています 本記事は誤っています。 実際の jest ランタイムの解説として不適切な箇所があります。jest ランタイム難しい… 時間があるときに直そうと思ってるんですが時間が取れません… とりあえず本記事を参考にしないでください。 本文 毎…

YouTube のスワイプで消せるフロートカードを実装する

最近のYouTube君がよく使うこのUIパターン、名前ついてるのか気になってる(フロート型で下スワイプで消せて上部にバーがついてるやつ) pic.twitter.com/EJeLQ8wSoS— クロパンダ (@le_panda_noir) 2022年8月12日 ↑これを CSS + JS で作りました。フロートカー…

Prettier は結局何をやっているのか?コードの動作は変わってしまわないのか?

結論: AST を作って、それを元にコードをフォーマットしているから、プログラムの動作は一切変わらない 結論をもう書いたので、意味が分かった人はここより下は不要。ちょっとだけ用語とかの解説をする。 そもそも AST とは? AST とは Abstract Syntax Tree …

touchcancel イベントをハンドリングしないと iPad で大変なことになるぞ

結論: iPad は4本指で上にスワイプするとホーム画面に戻る便利機能があります。これをブラウザで行うと touchstart → touchmove → touchcancel の順で発火します。 touchend が永遠に発火しません。 結論で言いたいことは完結してるので、以下はその補足説明…

zx を使っていい感じに SIGINT を捌く

シェルスクリプトで ctrl + C を押して中断したときのクリーンアップ処理を書くのはそこそこ大変です(頑張ればできますが)。今回は zx を使った、クリーンアップ処理を含むコードの書き方を紹介します。 そもそも zx とは? alt シェルスクリプト的なものです…