特にクイズを作りたかったわけではないですが、JSについて興味深いコードを何個か見つけたので列挙しました。
ES2015を念頭に書いてます。
Q1
-~function (){}
Q2
Object.create(null)
Q3
function a() { this.p = 100; return {p: 0}}
new a().p
Q4
9999999999999999
Q5
true + true - false
Q6
[]["toString"]["constructor"]("return this")()
Q7
'🍣🍣🍣'.length === [...'🍣🍣🍣'].length
Q8
function tag() {
console.log("hello world");
}
tag``
Q9
(![]+[])[+!![]]
解説
Q1
JavaSctriptでは暗黙のうちに型の変換がかかります。
function のビット数は0000
であるためにビットを反転させるとFFFF
= -1 となります。
Q2
一見すると単純な{}
のオブジェクトが生成されているようですが実は両者には違いがあります。
{}
で生成されるオブジェクトはObject.prototypeを継承していますが、 Object.create(null)
で生成されるオブジェクトはいかなるプロパティも継承していません。
例えば
var a = {}
a.toString() // "[object Object]"
var b = Object.create(null)
b.toString() //Uncaught TypeError: b.toString is not a function
このようにObjectのプロパティを一切継承しないオブジェクトが出来上がります。
ちなみに Object.create(undefined)
はエラーが発生します
Q3
new
のオペレータは少しトリッキーです。
new のオペレーターはfunctionが値を返さない時に限ってオブジェクトを作成します。返却される値が 数値や文字列などのプリミティブ型の時はその返却値を無視してオブジェクトを生成してくれます。
function a() { this.p = 100; return 'abc'}
new a() // {p: 100}
Q4
JavaScriptは常にNumber型で数値を持っています。また有効桁数はIEEE754に基づいています。
64bit中の
- 数値部分が52bit
- 指数部分が11bit
- 補数に1bit
つまり16桁以上は正確に計算できずに丸誤差が生まれてしまいます。
ただこれはJavaScriptに限った話ではないですね。。。
対応はライブラリを使用するのが良いでしょう。
Q5
前述の通りJavaScriptでは暗黙の変換がかかります。
つまり Number(true)
は 1
であり Number(false)
は0
として計算されます
Q6
全てを[]
で表現しましたが、periodでつなぐと見通しが分かりやすくなります。
[].toString.constructor("return this")()
またfunction
のconstructor
はFunctionがオブジェクトが返却されます。
つまり
var test = function test(){}
test.constructor // function Function() { [native code] }
Function
は任意の文字列を評価することができます。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
評価された文字列はglobalを参照するのでwindowが取得できるということになります
Q7
emoji はUTF-8の文字コードを組み合わせて出来上がる文字列です。𠮷
とかも有名ですね。難しい漢字とかも振り当てられています。
普通に評価すると見た目の文字数と実際の文字数が異なるのですが Spread Syntaxを使ってやるとうまく文字数が取れるようになります。
単純に配列にするだけでは以下のようになってしまいます。
'🍣🍣🍣'.split("") //["�", "�", "�", "�", "�", "�"]
splitではなくてこのように処理するのと同値です。
Array.from('🍣🍣🍣') //["🍣", "🍣", "🍣"]
ただ
[...'👨👩👧'].length // 5
'👨👩👧'.length // 8
これはあってるのか。。。。
unicodeもっと勉強しないとよくわからないってのが本音です。
参考
https://mathiasbynens.be/notes/javascript-unicode
Q8
Template literal は式を扱うことができる文字列リテラルです。
この使用方法はTagged template literalsと呼ばれます。Template literalの前にあるFunctionを評価して引数を与える動きをします
MDNにはもっと詳しく書いてあるので詳しくはこちらで。
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Template_literals
Q9
-
(![]+[])[+!![]]
!![]
はtrue
と評価される -
(![]+[])[+true]
+true
は 1と評価される -
(![]+[])[1]
![]
はfalse
と評価される -
(false+[])[1]
+[]
は文字列のキャストを行う - 'false'[1]
a
となります。
まとめ
一瞬見た感じわからなかった構文を自分の勉強の意味も込めてまとめてみました。
これら全てはどこかのページで見てそれをここに転記しているだけですが、もっと面白いもの等ありましたら教えていただければ嬉しいです。
参考
http://www.w3schools.com/js/js_numbers.asp
https://github.com/aemkei/jsfuck <= ほとんどこれで知ったもの