Here's a quick explanation:
> []
[]
> +[]
0
> !+[]
true
> +!+[]
1
Lesson: + as a prepend coerces things into numbers
> 123
123
> 123+[]
"123"
> ![]
false
> ![]+[]
"false"
Lesson: + as an infix operator between incompatible types coerces everything into strings
> Function("alert(123)")
function anonymous() {
alert(123)
}
> Function("alert(123)")()
[alerts 123]
Lesson: the Function object can be called with a string to make a function that evaluates that string
> [].constructor
function Array() { [native code] }
> ({}).constructor
function Object() { [native code] }
> (function(){}).constructor
function Function() { [native code] }
> (function(){}).constructor("alert(123)")()
[alerts 123]
Lesson: the constructor property returns the type of an object, and this gives you access to the Function object
> [].filter.constructor
function Function() { [native code] }
> []["filter"]["constructor"]
function Function() { [native code] }
Lesson: an array's "filter" method is a function and has Function as its constructor. Well, duh.
> [][[]]
undefined
> [][[]]+[]
"undefined"
> !![]+[]
"true"
> ![]+[]
"false"
> (!![]+[])[1]
"r"
> (!![]+[])[+!+[]]
"r"
Lesson: we now have the letters adefilnrstu, so we can construct []["filter"].
> [].filter+[]
"function filter() { [native code] }"
> ({})+[]
"[object Object]"
Lesson: we now have acdefijlnrstuv, so we can write []["filter"]["constructor"] and thus call our pseudo-eval on anything we can make as well.
> Function("return console")()+[]
"[object Console]"
> Function("")+[]
"function anonymous() {
}"
> 0["constructor"]+[]
"function Number() { [native code] }"
> '0'["constructor"]+[]
"function String() { [native code] }"
> Function("return assert")()+[]
"function assert(condition, opt_message) {
'use strict';
if (!condition) {
var msg = 'Assertion failed';
if (opt_message)
msg = msg + ': ' + opt_message;
throw new Error(msg);
}
}"
Lesson: we now have all the letters we need to make ""["constructor"]["fromCharCode"].
> String.fromCharCode(74)
'J'
Lesson: Enjoy the rest of the alphabet. We can now construct arbitrary programs and eval them.