-2

can anyone explain to me what is JS doing here? Can anybody explain what is going on here in terms of type coercion, IIFE, and closures?

Function.prototype.toString = (
    function() {
      const toStringFnRef = Function.prototype.toString;
      
      return function() {
            return `start:${toStringFnRef.call(this)}end`;
        }
    }
)();

console.log(1 + function x() { alert('hi') });
//output: "1start:function x() { alert('hi') }end"
  • 2
    Are you asking because this is code you want to avoid in future because it's terrible? – Andy Nov 05 '21 at 23:43
  • The type coercion is explained in the [specification](//tc39.es/ecma262/#sec-applystringornumericbinaryoperator), as is [`Function.prototype.toString`](//tc39.es/ecma262/#sec-function.prototype.tostring). `call` is explained in the [documentation](//developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Function/call), closures are explained here: [How do JavaScript closures work?](/q/111102/4642212). Please see [How much research effort is expected of Stack Overflow users?](//meta.stackoverflow.com/q/261592/4642212). What, specifically, is unclear? – Sebastian Simon Nov 05 '21 at 23:47
  • Related: [How to override Function.prototype.toString](/q/26697520/4642212) – Sebastian Simon Nov 05 '21 at 23:49
  • @Andy Question that came up in an interview – ehehe341 Nov 05 '21 at 23:53
  • And my answer to that question would be "I wouldn't touch that code with a barge-pole. Is this code indicative of the code I would be expected to engage with?" There are much nicer ways of trying to get interviewees to explain closures and IIFEs. – Andy Nov 06 '21 at 00:06
  • 1
    @Andy Haha I wish I could say that, but this is company that I really wanted – ehehe341 Nov 06 '21 at 00:44
  • Yeah, maybe that was a bit harsh, but I've been in the game for a long time and done a lot of ridiculous interviews. My question to them would be why they think it's appropriate to add a new method to the function prototype, and what they hope to achieve. As you get older sometimes you have to say "this is just bad code". But I wish you well for your job hunt. @ehehe341 – Andy Nov 06 '21 at 01:05

1 Answers1

0

The IIFE is being used to create a local scope where the variable toStringFnRef contains the original value of Function.prototype.toString. Then it redefines this with a function that calls the original function and wraps the result in start: and end.

This could also be done using a lexical block (in ES6 most IIFEs can be refactored like this):

{
  const toStringFnRef = Function.prototype.toString;

  Function.prototype.toString = function() {
    return `start:${toStringFnRef.call(this)}end`;
  }
}

When you do 1 + function x() { alert('hi') } it converts both 1 and the function to strings so it can concatenate them. So this calls your redefined Function.prototype.toString(), which surrounds the normal string of the function with those wrappers. This is then concatenated with 1.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Might be a stupid question, but how is the function definition: alert('hi') being outputted, would "this" represent function x() { alert('hi')? – ehehe341 Nov 06 '21 at 00:02
  • `this` in a prototype function is the object it's being called on. So if you have `f = function() { ...}` and you do `f.toString()`, `this` will be the value of `f`. – Barmar Nov 06 '21 at 00:03
  • @ehehe341 See [How does the "this" keyword work?](/q/3127429/4642212) and [the specification](//tc39.es/ecma262/#sec-toprimitive). Note that ToPrimitive with argument `input` implicitly invokes (among other things) the equivalent of `Object.getPrototypeOf(Object(input)).toString.call(input)` which boils down to `input.toString()`; `input` is the function, in this case. – Sebastian Simon Nov 06 '21 at 00:09
  • So why do we have to return a function() instead of just returning: return `start:${toStringFnRef.call(this)}end`; ? – ehehe341 Nov 06 '21 at 00:22
  • Because the value of `Function.prototype.toString` has to be a function. – Barmar Nov 06 '21 at 00:46
  • Isn't the return value of Function.prototype.toString a string though? – ehehe341 Nov 06 '21 at 00:50
  • @Barmar By value, do you mean the return value? – ehehe341 Nov 06 '21 at 00:51
  • You get the string when you call `toString()`. You need to assign a function to `toString()` so you can call it later. – Barmar Nov 06 '21 at 05:29