JavaScriptの escape() は非推奨というか、将来的に無くなるから、今後は使わない方がいいみたいです。ブラウザによって実装が違いすぎるからみたいです。

しかし先程、たまたま欲しくて探してたコードをネットで見つけたと思ったら escape() が使われていて、しかも encodeURI() とか encodeURIComponent() に書き換えたら動かなくなるやつでした。なので自力で escape() を書いてみました。

今使ってる Chrome (78.0.3904.97) の挙動とMDNの記載を元に、自分が理解した仕様は以下の通りです。

  • 英数字はエスケープしない。
  • 特殊文字 @*_+-./ はエスケープしない。
  • 文字コードが 0xFF 以下なら %xx 形式でエスケープする。
  • 文字コードが 0xFF より上なら %uxxxx 形式でエスケープする。
  • エスケープ後の16進数は大文字にする。

移植した関数が以下になります。

function myescape(str){
	return str.replace(/[^a-zA-Z0-9@*_+\-./]/g, function(m) {
		const code = m.charCodeAt(0);
		if (code <= 0xff) {
			return '%' + ('00' + code.toString(16)).slice(-2).toUpperCase();
		} else {
			return '%u' + ('0000' + code.toString(16)).slice(-4).toUpperCase();
		}
	});
}

unescape() は知りません。

テストコード

以下のテストは通ってます。

function myescape(str){
	return str.replace(/[^a-zA-Z0-9@*_+\-./]/g, function(m) {
		const code = m.charCodeAt(0);
		if (code <= 0xff) {
			return '%' + ('00' + code.toString(16)).slice(-2).toUpperCase();
		} else {
			return '%u' + ('0000' + code.toString(16)).slice(-4).toUpperCase();
		}
	});
}

function _a(str) {
	const result = escape(str) === myescape(str);
	if (result) {
		console.log(str, '->', myescape(str));
	} else {
		console.log('expected:', escape(str), ', actual:', myescape(str));
	}
	return result;
}

console.assert(_a('abc123'));
console.assert(_a('äöü'));
console.assert(_a('ć'));
console.assert(_a('@*_+-./'));
console.assert(_a('!?\\あああ'));
console.assert(_a('あいうえお'));
console.assert(_a('/🍅🐤/'));
console.assert(_a('じゃsp9宇\r\nfjさ惣\n\ndだあお\tうあw'));
実行結果
abc123 -> abc123
äöü -> %E4%F6%FC
ć -> %u0107
@*_+-./ -> @*_+-./
!?\あああ -> %21%3F%5C%u3042%u3042%u3042
あいうえお -> %u3042%u3044%u3046%u3048%u304A
/🍅🐤/ -> /%uD83C%uDF45%uD83D%uDC24/
じゃsp9宇
fjさ惣

dだあお	うあw -> %u3058%u3083sp%uFF19%u5B87%0D%0Afj%u3055%u60E3%0A%0A%uFF44%u3060%u3042%u304A%09%u3046%u3042%uFF57