Original code:
var func = String.raw
`abc`.split('')
console.log(func); // ['a', 'b', 'c']Modified to see what's happening:
var sraw = String.raw;
Object.defineProperty(String, "raw", {
value: function(...args) {
console.log(1, args);
return sraw(...args);
}
});
var split = String.prototype.split;
String.prototype.split = function(char) {
console.log(2, this, char);
return split.call(this, char);
};
var func = String.raw
`abc`.split('')
console.log(3, func); // ['a', 'b', 'c']Result:
1 [ [ 'abc' ] ]
2 [String: 'abc'] ''
3 [ 'a', 'b', 'c' ]
String.raw`abc`is a member expression- EvaluateCall is called with arguments:
String.raw,`abc`, IsInTailPosition(String.raw). `abc`is parsed as a TL, specifically NoSubstitutionTemplate, and the result is an array containing a single TemplateCharacters entry, which is the string"abc".- The call to
String.rawreceives the template object argument which contains the string"abc"(https://tc39.github.io/ecma262/#sec-tagged-templates), does what it does and returns the result, which in this case is a string"abc". - The resulting string
"abc"has its.split('')method called, producing an array of characters:['a', 'b', 'c']which is then assigned toconst func;
Another way to look at it:
function noop(x) {
return x;
}
const func = noop(`abc`).split('');
console.log(func); // [ 'a', 'b', 'c' ]
I have no sympathy for that invalid use case.