T̡̨͈͇̟̼̱̤̹̠́͆̂̋̂̀̄̋́̚ö̴̮̬̙͎͈̳̯́̈́̄̿̔̿͌̀̈́̀̊͊͊̌̈̓̕ͅ i̷̢̛̖͈̗̇n̶̝͂̂̂v̸̹͈͍̮̰̺̰̯̬̀̋̎̃̅́̓o̸̢͈̪͍̦̫̬̪̬̞̫̗̅̑͊́̓͋̕̚k͉̣͆̄e̷̶̡̳̤̤͇̠̤̼̭̠̭͈̻͆̃́̒̂̊̇̂ ẗ̵̢̢̛͉̪͈̪̥̞̣̪̙́̈́̓̃̂̆̀h̨̗̻̰̱̳̅͂̎̇̽̃e̷̴̶̛̬̦̮̜̾̂̃͂̐̌̈́̄̾̈́̄̀̚̕ h͍̘̙̠̯̜̫̙̙̜̥͉̝̋͌̌́͋̽͋̉̂̊̄i̶̡̢̧̧̨̛̯̬̤̭͇͂́̏͂̐̋̈́̎̍̋̀̐̕v̸̡̢̛̤̫͇̹̱̗̮̻͈̳̄͆̓̄̾̀̋̀́̕ȩ͍̹͂-m̴̶̳̖̼̟̅̓ĭ̴̠̙̦̗͍̙̀̒͂͌ņ̵̵̨̼͇̖̥̉͂̓̌̀ḓ̛̛̗̠̰̞̫̗̘̗̖̖̎̈́̐́̈́̑ͅ ṟ̯̟̟̣͍͈̰̫͌̓̆̽̈́̆̀̊e͎̜̭̣̝̪͂̒̔̽̕p̸̧̡̨̛̛̤̦̹̩͉͎͈̬͍͈̞̈́̀̉̿̈̄̒̊̇̽̚ͅȓ̶̵̴̳̘̟͈̓e̬̟̝̎̍s̶̷̷̡̛̪̞͇̼̤̱̘̼̘̘͈̮̃̾̑̆̑̆̏̈ͅe̢̬̳͈͉̙̖̖̱̭͈̣̪̲̱͎̔̓̅̎͋̃͋̾̂ͅņ̸̷̶̷̸̻̱̻̹̻̥̹̟̭̘̟̟̣̟͊̔̏̔̀̐͆̋̚ͅt̶̵̢͍͈̳̱̬̫̯̣̾̂̆̓i̷̸̧̛̛̹̹̯̬̜̪̼͇̮̤̯̖̾̀̄̃͌̃̄̓̔̋̏n̴̛̩̗̦̟̖̣̒̓̈̒̓̏̇̈́̓̽̉͊̑͌́͋̚ͅͅg̛̬͉̳̗̈́ ċ̵̶̨̠̘̮̤̺̟̹̱̠̙̅̑̽̽̃̐́̀̅̃̾ḩ̤̖̮̖͈̣̘̺̱̍̎͋ȧ̸̴̴̡̨̢̧̘̩̥͉̣̰̝̘̪̠̖͉̐̋̇̏̊̚̕ͅö̵̩̼̰̣̟̱̳̞̖̪̗͎́̃́́̆̍̓͌̀̽̃̊̿s̸̼̱͇̿̍͊͊
[].concat(...[...document.all].map(e => [...e.childNodes])).filter(n => n.nodeType === Node.TEXT_NODE).map(n => n.textContent = n.textContent.replace(/([a-zA-Z])/g, (_, c) => c + [...Array(Math.floor(Math.random()*30))].map(() => String.fromCharCode(0x300 + Math.floor(Math.random()*79))).join('')))
Ç̵̶̶̡̛̱̘̤͉̘̹͈̳̝̝̽̆́̀̈́̾̍̅̎̑̌̿̚ͅȯ̷̳p̶͍̲͇̳̔̅̍̚y̴̸̵̢̡̭̖̩̫̘̼̦̬̓̿̇͋̉͊̓́́́̑̍ a̴̵̶̢̛̟̬̘͍̰̝̘͌̍̈́̉̔̂͋̊̑̍̽̚̕n̸̵̢̢̧̛̛̪̬̯̠̣̮̤̮̻͈͈̘͌͋́̓̏̀́̋d͇͎̝̜͈͇͂̋ p̄a̴̸̴̛͉̰̯̗̯̯͉̰̲͈̤̞̽͂̃̔̔̅̒͂̑́s̢̝̮̳̳̮̪̞̟̃̾̑̅̒́͊t̷̨̨̫̣͇̮̮͍̺̭̓̈̎̇̔̈́̆̒̌̕̕ĕ̢̢̡̤̗̟̫̄̀̚ t̶̸̢̥̘̫̮̹̤̉̑̀̀̽̔̑h̸̝̝̀͊̅e̵͇̖̞̹̅͊̄̋̄̐̑̑ c̼̞̠̯̜̹̺̱̖͈̙͎̔̈́̽̓̔́̄̾̋̾̓͊̅̾̔̚̚o̵̢̥̘͍̱̗͈͈̭̟͇̠̰̪̮̩̿̂̅͌̀̀͌̀̑̆̆d̡̡̳̣̪̦̩̟͉̝͇̬̼̺̖̫̏̈́̅̇̍́̓̎̋ͅͅe͉̦͆͂̉̔ a̛̺̥̜̤͈͍̠̠͍̣̳͌̍̊̉̎̑͌̇̊̾̽́̒̒̾̏b̸̶̭̙̥̥̱̫̮̜̌͌̋̿̍̓ò̵̸̻̟̰̗̯̥̭̈́̾͌͌̃̾̊̽̽́̑̉́v̳̗͊̄͊̓̔̅́ḙ t̴̶̵̡̧̮̯͍̟̝̭̲̮̰̰͇̺̪͊͋͋̓̽͆̽́̂́̂o̧̜̖̟̼̥͎̭̩̟̳͍̅̓̾̏̎̀̅̍̐͆̈͊͆ t̷͉̣̺̗̰̱̏͊̎̂̇̆ḩ̨̜͎̳̺̥̬͊́̇̒̾̐̏e̛͉̝̙̓̀̓̾̑̚ ȃ̵̡̢͎̖͈̬̾̓̃̓̋̊̏͆͆̆̋̿ḑ̡̩̦̬̬̻͎̏̑̍͋͆̊̽̊́̾̐̏̈̀̽̎̚d̸̨̼̭̥̮͉̯̥̬͈̦̦̠̯̺̮͆̏̄̄͊̽́̏̽̓̏̂̕r̙̤͊̔̀̾e̷̡̹̜̫͍̻̥̋͂̓́͋̍̆s̸̷̨̡͈̲̰̮͇̦̪̟̭͈̲̟̀͌̋͂̔͊̍̓̏̿̕s̆ b̴͍̰̖̹̉à̲̱̬ŕ̤̙̫͎̻̞̥̼̮̑͂ a̳͉̲̲̗̮̰̜̾̏̅̄͌̿̂̕n̸̸̛̦̹̥̺͈͈͂̂̎̌̈̒̀̔̽̏͂̆̍ͅd̗̀̉ ṗ̶̭̲̠̞͌̄r̸̷̨̡̨̛̺̫͎̞̤̣̭̠̞̣̼͊̀̅̓̈́̔̈́̚e̷̴̢̨̻̱̳̼̘̘̍̄́̓̽̒̔̽̃̍̓̄͌̒̏̆̀̚̚p̶̨̧̯̟̪̙͍̖̪̌̓̇̈́̐͋̅̕e̷̸̢̧̝̘̜̭̠̘̰̗̋̀̀̏͆̐̈́̌͆̌͆̏̕ͅņ̶̡̻̼̩̼̙̖̰̯̤͈͇̦̬̈́̂̒̀́͋̆̿͂͆̚d͆̉ͅ "j̺̙àv̴̖͍̀̿̽̏͆a̭͉̞͇͎̓͌̔͋s̸̢̢̡͎̲̯̙͈̳̱̟̹̱̤͎̏͂̅̄̒́̈̔̆̀ͅc̴̡̪̳͎̤̭̺̗̟͂̀̎́̏͆̒̈́ȓ̸̢̨̭͎̠̪̜̣̈͆̒͌͂͌̎͆͋ĩ̲̞̰̤́̄p͇̀̓͆́ţ̴̷̺̯̫̯̻̯̹̺̠̲͈͉̤̍̔̔̌͂̀̓́̂́͊́̕:", ẗ̷̢̯̮͇̗͈̦̫̮̼͆̔́̾h̖̰̲ȩ̛̝̥̘̯̠͉͂̊̓̚n̟̼̩͊̒̈ ṕr̴̨̦̭̦̪̺̟͊̃̂̑̾́̂́̆̀é̇s̷̨̪̤̮̟̗̿͂̐͌̈́̓̅s̵̛̭̤̩͎̦̳̠̘͈͍̜̒̏̽͂̃́̏̏̀ͅ Ě̸̦̱̙̭̠̯̬̂́́́̋̏̐̆̕ṅ̠̼̳̮̌̌͌̊̽̓ţ̷̶̡̨̛̩̰̜̪͇̫̘̯̱͈̙̯̜́̾͆̌̒̏̓̚ȩ̼̻͈͊̍̑̎ṟ̡̜̘̩͉͂̔̀̀̈́̐ k̵̡̲̮͉̣̲̜̰̺͎̺̲̒̅̓̓̿̐͂̊̂̌̋̉̀ͅe̸̵̯̣̥̣̝̒y̭̜̞̠̳̺͆̑̆͌.
注意
実行には数秒くらいの時間が掛かります。
Googleの検索結果ページ等だと、何故かページのスタイルが崩壊してしまいます。
GitHubとかのページでやると良いでしょう。
(追記: スタイル等が崩壊するのは<style>
や<script>
の中身が変わるためのようです。こいつらもTextNodeなのか)
解説
ZalgoするJavaScript(ES6)ワンライナーです。
JavaScriptの闇がいくつか詰まっているので1つずつ説明しようと思います。
まずprettifyするとこんな感じ
[].concat(...[...document.all].map(e => [...e.childNodes]))
.filter(n => n.nodeType === Node.TEXT_NODE)
.map(n =>
n.textContent = n.textContent.replace(/([a-zA-Z])/g, (_, c) =>
c + [...Array(Math.floor(Math.random()*30))].map(() =>
String.fromCharCode(0x300 + Math.floor(Math.random()*79))
).join('')
)
)
[].concat(...arrayOfArrays)
(編集しました。元は Array.prototype.concat.apply([], arrayOfArrays)
としていましたが、ほぼ同じ意味です)
Array.flatMap をしたい時はこうするしかありません。 ふざけんな
配列の配列(arrayOfArrays
)を全て結合して1つの配列にします。
(追記: いつの間にか Array.prototype.flatMap
が標準に入ってました)
今回は全てのelementに対してそれぞれのchildNodeの配列を取得するので、Nodeの配列の配列が出来ます。これを単なるNodeの配列にするわけです。
[...iterableObject]
document.all
とか element.childNodes
とかはただのIterable
であってArray
ではないため、 map
が出来ません。
そのため、上記のような spread operator (...
) を配列リテラルに使うことで無理やりArrayにします。
ページ内の全てのTextNodeを取得する
まとめると、以下でページ内の全てのTextNodeを取得することが出来ることになります。
[].concat(...[...document.all].map(e => [...e.childNodes]))
.filter(n => n.nodeType === Node.TEXT_NODE)
[...Array(n)]
例えば、 Array(10).forEach(() => console.log('foo'))
としても何も出力されません(forEach
をmap
に変えても同じ)。
Array.prototype.forEach
も Array.prototype.map
も、値がまだ代入されていないインデックスに対してはcallbackは呼び出されないのです。
一方で、[...Array(10)].forEach(() => console.log('foo'))
とすると "foo" が10回出力されます。
これは、 Array.apply
に 10個の undefined
が引数として渡された結果length
が10
のものがargumentsとして渡された結果、0から9までのindexに undefined
が代入されたことになるからです。
(ここの解釈はちょっと合ってるか怪しい...)
Combining character
Unicodeには実にいろんな文字があります。
上記の U0300-U036F の範囲の文字は Combining character といって、直前の文字の上や下や真ん中にくっついてしまいます。
2文字以上の combining character が続くと、全ての combining character が前の文字にくっついて、上や下にズラーッと並んでしまいます。
スペースや日本語等の文字にはくっつかず、横に続いてしまうため、今回のスクリプトではアルファベットだけにくっつけるようにしています。
また、私の環境だと□になってしまったりしたので上記の文字のうち一部のみを使用しています。
おまけ
特定の文字列だけ変換したいことってありますよね。この記事を書くときとか。
'Any string here'.replace(/([a-zA-Z])/g, (_, c) => c + [...Array(Math.floor(Math.random()*30))].map(() => String.fromCharCode(0x300 + Math.floor(Math.random()*79))).join(''))
H̸̘̖̲̙̊̅̉̓̓̈́̏͋̕ȩ̨̡͈̰̟̹̝̒́̈̔̏̓̑̾ ẃ̶̷̨̢̢͎̟̦̺̗̥̗̘̓̓h̾ơ͈̯̭̝̞̊̃̎̉͊̾̾͆̂͂̚ W̸̶̷̢̟̲̙̮̫̭̫̾̇̆͌̆a̵̢̛̻̩̩̦̟͎̜͈̭͎̙̼͂̐̃̏̐̈́̇̇̚ī̤̫̘̈̑ṭ̸̢̛̟̰̖̝̬͎̥̝̀̏̅̎̇͋̀̈́̐̈́̓̎̑̂̓̚s̶̵̱̘̦̍͊ B̧̫̦̫̮̤̻̖̌̓e̷̛̳̮̺̤̳͎̮̳̲̐̎̔̋ͅh̶̹͍i̿̎̔̀ͅǹ̷͍̦̭̮̜̖̱̈̂̓̒͂̂ḑ̸̺̪̞̪̜̗̰̜̻̗̓̒̒̈́̍͊̏̄̉̒̍̾̽̌́̕ T̵̡̛̪̩̙̜́̌̅̃͂̏̾ḩ̸̞͈̞̯̥̣̹̩̫̤͂̇̀̀̾̇̆̔̽̎͊͆̄̾̂̚e̵̩̬͈̙̍̆͌̐ W̵̡̠̣̩̳̪͉̰̮̪̭̘̣̐́̈́̇̌͌̎́̐̂̎ͅa̡̢̩̯̘͎̻̺̹̞̔͊̽͋̏̐l̷̷̢̢̧̢̛̙̖̤̗̲̠̫̠̹̋̇̇́̚ĺ̴̵̴̸̻̗̬̪̙̠̥̘̙̙̆̃̋̉̑͌͌̾̄͆̚ͅ