◆ 標準機能にあって欲しい機能のまとめ
◆ 色々入れると重くなって気軽に入れたくなくなるので最小限に
◆ Gist に package.json つけたので npm で入れれる
  ◆ Gist の ID 覚えないと毎回調べることになるけど

jscoreutils

JavaScript で標準にあってもいいと思うのに無い機能がいくつかあります
その中で関数を作って対応できるものをまとめました

jscoreutils

HTML のエスケープや正規表現のエスケープや日付のフォーマットなどです

ES2015 以降は色々機能が増えていて入っててもおかしくないと思うのに入ってくれません
コードにするとそこまで長くないけど短くもない長さです
割と頻繁に使いたいもので 毎回書いているとさすがに面倒です
探してきてコピペも手間です

これらが入った便利機能まとめなライブラリはありますが その他ほとんどが要らないのにそれだけのために入れるのは過剰すぎて抵抗があります
かといって一つ一つの機能だけのライブラリをいくつも入れるというのも気が進みません

そういうわけで最低限欲しいと思う 標準に合っても良さそうな機能をまとめました
とりあえず勢いで作っただけで最低限の動作確認しかしてないです

含めるもの

あれも欲しいとかで色々入れだすと ごちゃごちゃしてきて結局これだけのために入れるのもなぁ となってしまうのは何度も経験してるので最低限の標準であってほしいものだけにすることにしてます

機能一覧

その基準で選んだのが一覧がこれです

  • 正規表現の escape
  • HTMLの escape
  • HTMLの unescape
  • 配列のシャッフル
  • 配列の sortby
  • 文字列の split
  • 日付のフォーマット
  • JSON として等しいかチェック

escape 系と日付フォーマットは言うまでもなく必須だと思います
日付フォーマットの指定方法は Python に合わせましたが 使わなそうなオプションは入れてません

配列のシャッフルは入れるべきか迷ったのですが ダミーデータ作ったりとかで少なくない頻度で使うもので 実装も毎回書くのはちょっと面倒なので入れることにしました

sortby は一応 sort メソッドはあるのですが低レイヤー的すぎて使うのが面倒すぎます
配列の要素 2 つからそれぞれ比べる値を取り出して比較結果を -1, 0, 1 で返す必要があります
プロパティ名や関数で値を指定したらその値に応じて自動でソートしてほしいことがほとんどです
複数条件の組み合わせも sort メソッドのコールバックで自分で工夫してやるしかないです
そのあたりを楽にする sortby メソッドはあってもいいと思うのですけど
作った sortby 機能では asc/desc をサポートしてません
コールバック関数が返す値を逆になるようにするか sort 後に reverse すれば済むので機能的にはシンプルにしました

split もあるにはあるのですが 数を指定する機能が使えなすぎます
最後の要素に残り全部が入っていてほしいことが多いのに最後の要素も分割後のものになります
「a:b:c:d:e」を「:」で分割して 3 つに分ける場合「"a","b","c:d:e"」を期待してるのに「"a","b","c"」になります
◯個に分割ではなく分割して◯個取り出すという挙動です
結果的には全部 split してから slice すれば取得できるものです
余計な分割をしない分 パフォーマンス的には意味がありますが機能的に求めてるものじゃないです
最後に残りが入るようにしていれば 1 つ多めに分割して最後を捨てればいいわけですし
現状のだと残りを取得する手段が 全部分割して残りを分割した文字で再結合するというムダの多い方法しかないです
なので求めてる split を作りました

オブジェクトの再帰的な比較は JavaScript ならあってもよさそうなのに JSON 文字列化して文字列比較するしかないです
オブジェクトの比較はちゃんとやると getter / setter とか循環参照とか非列挙プロパティとか prototype とか考えることが多すぎるので 再帰的にチェックがベストですが現実的には JSON で十分です
ただ 文字列化する方法だとプロパティの並び順によっては別物扱いされます
自動でプロパティ名でソートしてくれません
なのでソートして JSON 化してチェックするものを追加しました

入れないもの

あったほうがいいかなとは思ったもののやめたものです

sum は reduce で足せばいいですし average は sum を割るだけですし
配列の intersect, diff, xor は filter で済みますし
オブジェクトの filter や map 系は Object.entries / Object.fromEntries を利用して配列操作でいいです
オブジェクトのコピーも JSON 化できる部分だけでいいので stringify して parse するだけです
この辺は関数化するにしてもわざわざインストールするよりその場で作るほうが速いです

DOM 操作系や localStorage や fetch 関係は毎回する面倒な部分があるのですが ブラウザのみなので入れないことにしました
あくまで JavaScript 全般的なものにしてブラウザや Node.js その他 V8 エンジンが動くようなところで使えるものに限定しました
ECMAScript にあってほしい機能という基準です

crypto 系はブラウザと Node.js で別々のものがあるので同じ使い方でもっと楽に使いたいですが そのラッパーを入れるのもなぁと思いますし別ライブラリとしてあったほうがいいと思うので入れてません
csv 関係とか シード指定できるランダムも標準機能としてあってもいいと思いますが 規模が大きめでここに入れるというより独立したライブラリのほうが適切な気がするので含めないです

String.raw のようなテンプレートリテラルのタグ関数でエスケープ機能を入れたい気もしましたが エスケープ自体があれば簡単に作れるのでなしにしました

一番悩んだのは配列初期化です
入れるほどでもないと思うのですが毎回書くのがすごく面倒です
JavaScript の Array は要素数指定で作っても empty な状態で map 対象になりません
Array.from(Array(10)) や [...Array(10)] や Array(10).fill() みたいなことをしないといけません
ただ それぞれの中身はどれも undefined なので要素番号がほしいなら コールバック関数で 2 つめの引数が必要になります

Array.from(Array(10), (x, i) => i)

これも地味に面倒なので .keys() にして配列自体に要素番号が入ってる方が扱いやすいです

Array.from(Array(10).keys(), x => x)

配列の要素を初期化する以外にも同じ関数を◯回実行したいということもあるのでこれを関数にしておけばどちらにも使えます

const callTimes = (fn, count) => Array.from(Array(count).keys(), fn)

callTimes(addElement, 10)
const a = callTimes(x => Math.random() * x, 100)

結果がいらないなら返り値を捨てればいいだけです
ただ標準にあるべきかという考え方だと escape などとは違い浮いてる気もします
どちらかというと連番が入った配列を作る機能だけのほうがそれっぽいです

const seq = n => [...Array(n).keys()]

結果の配列に map すれば配列初期化に使えますし forEach すれば指定回数の関数実行にできます
ただここまで短くなるとわざわざ関数用意する必要ないように思います
日付フォーマットとかは使わなくて ほしいのがこれだけだった場合にわざわざインストールするかというとしないです
その場に自分で関数作れば済みますし


それともうひとつ代入形式の console.log も欲しかったですがこれもやめました
console.log は関数なので出力したいものは引数です
つまり () で囲む必要があります
これが面倒かつ見づらくて 代入形式のようにして出力したいです
C++ の count << 的なものです

log = something()

setter を作るだけなので実装は難しくないです

Object.defineProperty(
globalThis,
"log",
{ set(v) { console.log(v) } }
)

ただ標準的ではないことやその場で作るのに対して苦労しないので入れないことにしました


色々ボツにしてると ひとつひとつは短く書けるけど数が増えると全部書くとそこそこの量になりますし 都度書くのは面倒なので短く書けるけどよく使う系の機能まとめも作りたくなるんですよねー

使い方

package.json 付きの Gist なので npm でインストールできます

npm install gist:0c77f428073201923fcc4ad111b04274

あとは import して使います

import * as utils from "jscoreutils"

console.log(utils.htmlEscape("<div>"))
// &lt;div&gt;

console.log(utils.dateFormat("%Y/%m/%d %H:%M:%S"))
// 2020/03/19 01:48:27

console.log(utils.stringSplit("a/b/c/d/e", "/", 3))
// [ 'a', 'b', 'c/d/e' ]

console.log(utils.arraySortBy([1, 18, 61, 10, 128, 41, 20], x => x % 10))
// [10, 20, 1, 61, 41, 18, 128]

ESModules なので Node.js だと import 元を .mjs にするとか package.json で type: "module" の指定するとか必要です