2

Function.name property is configurable and can be overriden, but if I try

function foo() {}
Object.defineProperty(foo, 'name', {value: 'bar'})

foo.toString() still shows up as "function foo() {}" but I expected it to be "function bar() {}".

hldev
  • 914
  • 8
  • 18
  • 1
    You cannot update the "name" property of a function object. – Pointy Oct 04 '21 at 15:51
  • Why would you want to change the output of `.toString()`? – Andreas Oct 04 '21 at 15:52
  • @Pointy - You can't update it (assign to it), but as the OP said, you *can* redefine it with `defineProperty`. But that doesn't change the string returned by `Function.prototype.toString`. – T.J. Crowder Oct 04 '21 at 15:53
  • @T.J.Crowder really? MDN describes it as "read-only", but that's MDN – Pointy Oct 04 '21 at 15:54
  • See https://stackoverflow.com/q/5871040/3001761, but you'll have to read beyond the first answer. – jonrsharpe Oct 04 '21 at 15:54
  • @Pointy - You can redefine read-only properties as long as they're configurable. `name` is configurable. – T.J. Crowder Oct 04 '21 at 15:54
  • Yep I just tried in the console. I'm too lazy to edit MDN however. – Pointy Oct 04 '21 at 15:56
  • @Pointy - [This](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name) looks right to me...? (Not nit-picking; just curious. :-) ) – T.J. Crowder Oct 04 '21 at 15:57
  • @T.J.Crowder well its *correct*, but using the term "read-only" in the fairly casual opening paragraph(s) seems like something that could be clarified. It has of course never occurred to me to update the "name" property of a function, but I've always assumed it was not modifiable and I'm pretty sure that assumption has played a role in one or more old answers to questions here. – Pointy Oct 04 '21 at 16:09
  • @Pointy - Yeah, the whole thing could use a bit of a style update. – T.J. Crowder Oct 04 '21 at 16:09

2 Answers2

5

You can't do this 100% reliably. That's because of the definition of Function.prototype.toString, which uses the [[SourceText]] internal slot, which is set as the function is being created from the source code that was used to create the function. It doesn't use the name property.

You could try to override toString on the function as well, but of course that would still fail if someone explicitly used Function.prototype.toString on it.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
0

If you just want to cheat with something like toString, maybe you can consider using Proxy.

Example:

const YouWannaChangeName = "modified";

function x(a, b, c) {
    return 0;
}

console.log(x.toString());

x = new Proxy(x, {
    get(target, prop, receiver) {
        if ([Symbol.toPrimitive, "toString"].includes(prop)) {
            return function () {
                const re = new RegExp(`^function ${target.name}`);
                return target.toString().replace(re, `function ${YouWannaChangeName}`);
            };
        } else {
            return target[prop];
        }
    }
});

console.log(x.toString());
console.log("" + x);

This is also valid for native functions.

Note: Until 2022, the browser environment doesn't provide any Proxy aware API. In fact, the spec also explicitly states that Proxy shouldn't be detected. So I think this method is reliable.

  • If you plan to deploy on server side like Node.js, or privileged environment such as browser extension, it'll be able to be detected.
  • If the target function is custom function, make sure it's dosen't have configurable: false and writable: false)
LianSheng
  • 448
  • 5
  • 17