JavaScript
es2015

謎だったJavaScriptのコードたち

More than 1 year has passed since last update.

特にクイズを作りたかったわけではないですが、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")()

またfunctionconstructorはFunctionがオブジェクトが返却されます。

つまり

js

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 <= ほとんどこれで知ったもの