1

I saw this way to execute the code:

[eval][0]('alert("hello")')  

I want to know what does unquoted 'eval' surrounded by square brackets mean and why this works. (For example, window['eval'][0]('alert("hello")') will lead to a TypeError). Is there any tutorials that describe such a syntax?

lyrically wicked
  • 1,185
  • 12
  • 26
  • 2
    Also note that `[alert][0]('test')` gives a `TypeError: Illegal Invocation`. This is because the `this` in `alert` that is normally bound to `window` is not bound when called like this (alert. `[alert.bind(window)][0]('test')` gives no errors. – Philip Ramirez Oct 22 '13 at 06:27
  • Also, view [question #4670805](http://stackoverflow.com/questions/4670805/javascript-eval-on-global-scope) for an example of *why* you'd want to execute `eval` in global scope. – Philip Ramirez Oct 22 '13 at 06:32
  • @lyrically wicked: You should mark Matteo's answer as the correct one...its the best answer. – go-oleg Oct 22 '13 at 15:53

4 Answers4

6

That is an indirect eval call

Quoting from the article:

According to ES5, all of these are indirect calls and should execute code in global scope.

So you can use these kind of "tricks" to execute eval in the global scope instead of the current one.

It works before [eval] is an array where its 0-th element is the eval function, that is, [eval][0] === eval, and you are invoking it passing the string 'alert("hello")' as the argument.

Matteo Tassinari
  • 18,121
  • 8
  • 60
  • 81
2

Unquoted eval surrounded by brackets is an Array with one element which is eval.

[eval][0]('alert("hello")')

means take the first element of the Array [eval] and pass 'alert("hello")' to it. In other words,

eval('alert("hello")')


window['eval'][0]('alert("hello")')

on the otherhand tries to get the first element of window['eval'] which is not an Array, and thus the TypeError. window['eval'] is the same as eval unless there is another variable in scope called eval.

go-oleg
  • 19,272
  • 3
  • 43
  • 44
2

The reason your example leads to a TypeError:

window['eval'][0]('alert("hello")')

is because you left out one set of brackets that would have made it equivalent:

[window['eval']][0]('alert("hello")')

The initial syntax you gave constructs an array with one element, the function eval. The 0th element of this array is therefore the eval function, which is immediately dereferenced using the square brackets.

Mike Edwards
  • 3,742
  • 17
  • 23
  • 3
    You might want to include why one might do this instead of just a plain `eval()` call. – Qantas 94 Heavy Oct 22 '13 at 06:14
  • According to [perfectionkills.com/global-eval-what-are-the-options](http://perfectionkills.com/global-eval-what-are-the-options/), `eval("code")` is a direct eval call (executed in the scope of a caller) and `[eval][0]("code")` is an indirect one executing in global scope. But why does it happen? As for me, I don't know... – lyrically wicked Oct 22 '13 at 06:54
1

In Javascript

[x]

is a list of one element containing x. thus

[x][0]

is just a wordy and inefficient way of saying x.

Your example

[eval][0]('alert("hello")')

is therefore just like

eval('alert("hello")')

This kind of trickery is normally found in Javascript trojan or viruses, where the author tries to disguise what is happening.

Javascript however is full of special cases and when used with eval the code can also have the meaning of forcing global evaluation instead of local evaluation.

function defun(s) { [eval][0](s); }
function defun2(s) { eval(s); }

defun2("function square(x){return x*x}")
---> undefined

square(12)
---> ReferenceError: square is not defined

defun("function square(x){return x*x}")
---> undefined

square(12)
---> 144

See Matteo Tassinari answer link for details (note that the linked article is a bit dated, so ignore details about webkit behavior).

6502
  • 112,025
  • 15
  • 165
  • 265