dragonfire dragonfire - 5 months ago 13
Javascript Question

Trying to understand the official ES6 spec regarding Symbol.hasInstance

The ECMAScript 2015 official spec on Symbol.hasInstance writes:


This property (referring to Symbol.hasInstance) is non-writable and
non-configurable to prevent tampering that could be used to globally
expose the target function of a bound function.


Now, even non-writable and non-configurable properties can be overwritten with Object.defineProperty() and indeed if you try to overwrite Symbol.hasInstance to always return true then it will do so.

I don't understand the quote though.

Presumably the scenario where the global function could be exposed is in the case of a bound function when you overwrite the target's Symbol.hasInstance to return true. Naturally it would return false because the target swaps its prototype onto the bound function, and therefore the bound function is not an instance of the target. Also, to my best understanding I believe the reason it would end up on the global scope is because a bound function has no prototype and therefore cannot physically be an instance of the target function, so if you force it as an instance then the target's prototype is forced on the non-existent bound prototype and it ends up failing and placing the target's
this
on the global scope. However, even when I set it to return true I still cannot get it to expose the target globally.

Note, this is something I am trying to do to better understand the inner workings of JavaScript. In practical application I wouldn't want to expose the target globally.

I have tried hours and hours of fiddling with a range of code snippets of bound functions and Symbol.hasInstance returning true but to no avail. I cannot get it to expose the target's functions and data globally. If anyone understands this better it would really be greatly appreciated. I've hit a brick wall.

Answer

Let's clarify, you are talking about section 19.2.3.6 of the spec, which is the spec for Function.prototype[Symbol.hasInstance].

The text in the most recent version of the spec is:

This property is non-writable and non-configurable to prevent tampering that could be used to globally expose the target function of a bound function.

What this is saying is that you cannot do:

// A malicious library loads here and overrides the function.
(function(){
  Object.defineProperty(Function.prototype, Symbol.hasInstance, {
    value: function(instance){
      const context = this;

      // Here, `this === SomeClass`
    },
  });
}();

// Some library loads here.
(function(){
  function SomeClass(){}

  const BoundClass = SomeClass.bind(null);

  var tmp = {} instanceof BoundClass; // true
})();

So in this example, if the property were configurable: true, a malicious library would be able to access SomeClass, which would otherwise have been an entirely private and scoped within an IIFE.