How does Chrome executes scripts inside Developer Tool

Recently, working with Chrome Developer Tool, I found strange thing, which at first was interpreted by me as a bug.
I wrote some code with pair of opening-closing brackets, like this “}{“ and I tried to execute it. Surprisingly, but it does not produce me any error. I was amazed…

I tried to execute another examples:

Sample Code
1
2
3
4
5
6
7
8
9
10
11
12
13
}{
// undefined
}+1-{
// NaN
}+"a"-{
// NaN
}var a = 10;{
// undefined
}{}{
// undefined
}console.log('yay!');{
// yay!
// undefined

Okay, it seems fantastic, because it’s not valid JavaScript expression. Let’s look deeper. I’ve put “console.trace()” in executed expressions and tried to figure out how it works:

Sample Code
1
2
3
4
(anonymous function) @ VM336:2
InjectedScript._evaluateOn @ VM118:895
InjectedScript._evaluateAndWrap @ VM118:828
InjectedScript.evaluate @ VM118:694

Now we can go through every stack trace item. First, “(anonymous function) @ VM336:2”. This call on the top of the stack trace that has following code:

Sample Code
1
2
3
with (typeof __commandLineAPI !== 'undefined' ? __commandLineAPI : { __proto__: null }) {
console.trace()
}

As we can see, Chrome wraps executed script. He does it because:

Only install command line api object for the time of evaluation. Surround the expression in with statements to inject our command line API so that the window object properties still take more precedent than our API functions.

Wrapping occurs on the next function call of the stack trace — on “InjectedScript._evaluateOn @ VM118:895”.

If we will take a look on the last two functions, we’ll find that they do “wrapping-result-exceptions” operations:

Sample Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// .. some code
evaluate: function(expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview)
{
return this._evaluateAndWrap(null, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview);
},
// .. some code
_evaluateAndWrap: function(callFrame, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview, scopeChain)
{
var wrappedResult = this._evaluateOn(callFrame, objectGroup, expression, injectCommandLineAPI, scopeChain);
if (!wrappedResult.exceptionDetails) {
return { wasThrown: false,
result: this._wrapObject(wrappedResult.result, objectGroup, returnByValue, generatePreview),
__proto__: null };
}
return this._createThrownValue(wrappedResult.result, objectGroup, generatePreview, wrappedResult.exceptionDetails);
},
// .. code

After it we can a little better understand what happening inside this useful and necessary in development process tool.

Originally, post was published at Medium.