JavaScriptのバイナリー文字列とatob、btoaの関係について

JavaScriptで atob と btoa を使用する際に扱う"バイナリー文字列"、Base64との関係も含めてしっかり理解できていなかったため覚え書き。

# バイナリー文字列(Binary strings)とは？
1. つまるところ charCodeAt で 0-255 の範囲の値を返す文字コード**だけ**で構成された文字列(string)の事を指す
1. 制御コード等も含むため文字としての表示は保証されない
1. ECMAScriptの言語仕様に特にそういう概念は無い
1. TypedArray登場以前にバイナリを扱うために利用されていたとか

(参照) [バイナリー文字列 - Web API | MDN (archive.org)](https://web.archive.org/web/20220602070938/https://developer.mozilla.org/ja/docs/Web/API/DOMString/Binary)

## バイナリー文字列はどこで使うの？
atob、btoaを利用する時。令和の今ではたぶんそこ以外ほぼない。 ~~知らんけど。~~

## そもそも atob と btoa は何をするもの？
**Base64**文字列と**バイナリ文字列**を相互変換する

* **atob**は**Base64**文字列を**バイナリ文字列**へ変換する 
* atobにBase64以外の文字を入力すると**エラー**を吐く。
* **btoa**は**バイナリ文字列**を**Base64**文字列へ変換する
* btoa に0-255範囲外の文字を入力すると**エラー**を吐く。

## 要するに atob と btoa はどこで使うの？
**Base64**からバイナリデータに戻したい、又はバイナリデータを**Base64**化したい時。代表的なのは Data URI 関連。しかしatob、btoaは**バイナリ文字列のための関数**なので、TypedArrayなどでやりとりするには以下のような変換処理が必要になる。

* TypedArray ⇒ バイナリ文字列 ⇒ btoa ⇒ Base64
* Base64 ⇒ atob ⇒ バイナリ文字列 ⇒ TypedArray

__バイナリ文字列自体に用はなくても必ずバイナリ文字列変換を挟まなければならない。__ 非合理だけど昔からJavaScriptについているBase64用の組み込み関数がこういう仕様だったのだから仕方がないという解釈で合ってるだろうか。

## 実際の使用例
### Uint8Array ⇒ バイナリ文字列 ⇒ Base64

```javascript
{
  let bin = new Uint8Array([0, 16, 65, 128, 144]); // Uint8Array (数値は適当)
  let bstr = String.fromCharCode(...bin); // バイナリ文字列化
  let b64 = btoa(bstr); // Base64化
  console.log(b64); // "ABBBgJA="
}
```

### Base64 ⇒ バイナリ文字列 ⇒ Uint8Array

```javascript
{
  let b64 = "ABBBgJA="; // Base64 (上のコードで得たBase64データから復元を試みる)
  let bstr = atob(b64); // バイナリ文字列化
  let bin = Uint8Array.from(bstr, str => str.charCodeAt(0)); // Uint8Array化
  console.log(bin); // Uint8Array(5) [0, 16, 65, 128, 144] // 元のバイナリ
}
```



# 以下余談
## atob、btoaの生まれと名称
"a"はASCII、"b"はBinaryを意味しているのは明らかだけど、実際の所はASCIIではなくBase64だし入出力に使用されているのはどちらも文字列型なので解りづらい。どうしてこんな名前なのかというと歴史的事情的なアレで仕方がないらしい。そんなに歴史があったの？

>In these APIs, for mnemonic purposes, the "b" can be considered to stand for "binary", and the "a" for "ASCII". In practice, though, for primarily historical reasons, both the input and output of these functions are Unicode strings.
(訳: これらのAPIは、覚えやすいように「b」が「バイナリ」、「a」が「ASCII」を表すと考えることができます。しかし実際には、主に歴史的な理由から、関数の入力と出力は両方ともUnicode文字列です。)

(参照) [HTML Standard (8.3 Base64 utility methods)](https://html.spec.whatwg.org/multipage/webappapis.html#atob)

知らなかったけどatob、btoaはかなり昔からNetscapeに搭載されていたらしい。以下のJavaScript作者氏のツイートによると、この名前は1995年にUnixから持ってきたものとのこと。

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Old Unix names, hard to find man pages rn but see <a href="https://t.co/lWkceMwFad">https://t.co/lWkceMwFad</a>. The names carried over from Unix into the Netscape codebase. I reflected them into JS in a big hurry in 1995 (after the ten days in May but soon).</p>&mdash; BrendanEich (@BrendanEich) <a href="https://twitter.com/BrendanEich/status/998618208725684224?ref_src=twsrc%5Etfw">May 21, 2018</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

なんでこんな名前付けちゃったの？というツイートに対する氏の連投を意訳すると、「名前なんてそんなもんだ。文句いうな、はげ」という感じでしょうか。

## Netscape Navigator 4を試す

1995と書いてあったが atob が実装されたのは1997年に出たNetscape Navigator 4.0(JavaScript 1.2)かららしいので確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1672448/a945c044-fe64-ee86-3707-67d80e43c308.png)
この時代からあったんですね…(IEは10から)