maxnordlund / function.prototype

Polyfill for Function.prototype.{apply,bind,call}
MIT License
1 stars 1 forks source link

Function prototype call and apply both don't work for a frozen context object #3

Open JasonRammoray opened 6 years ago

JasonRammoray commented 6 years ago

Example:

var obj = {foo: 42};
Object.freeze(obj);
function t() {console.log(this)}
t.call(obj);

As a result we get a runtime error (Uncaught TypeError: object[symbol] is not a function), because function hasn't been added to a context object, because the latter was frozen.

JasonRammoray commented 6 years ago

@ maxnordlund, please, keep in mind, that not only a context object might be frozen, but also each and every prototype in the object's prototype chain.

maxnordlund commented 6 years ago

True, but I don't think any JS engine old enough to need this implements Object.freeze. I don't have the tweet at hand, but I did ask someone doing research on these old engines, and try/catch is not a thing. So this needs to be fixed as well, but I didn't get a VM running old Netscape and IE.

Edit: Here's the tweet https://twitter.com/nevonnen/status/916565339370131456

JasonRammoray commented 6 years ago

True. Object.freeze has been shipped to Firefox 4 / IE 9 / Chrome 6 / Opera 12 / Safari 5.1, which are not so old enough browsers compared to Netscape. Yet I think it is a good idea to test if object is immutable (for example, by adding a property to it and checking if it is there afterwards). There should be another strategy in case of immutable context. What do you think?

maxnordlund commented 6 years ago

After looking around a bit, and reading the first version of ECMAScript-262 it seems like you can use the typeof operator to figure out if Object.freeze is available.

But according to MDN it was first implemented in JavaScript 1.1, which translates to Netscape 3.0.

Since this project tries to work in those ancient browsers that doesn't work. Both instanceof and try/catch is even younger, introduced in ECMAScript 3.


After reading some more, and finding the changelog for 1.1 I've realized I need 1.1 in order to support Function.prototype at all. So the typeof solution will work.

Now the real question is how to implement this for frozen objects. I don't think it's possible, AFAIK there's no other way to set the this context without modifying the object itself. You could inherit from the object, mutate the resulting instance and call it like so. But then any modifications will end up on the temporary object. Which is really confusing as it should explode, being frozen.

That would look something like:

function TempClass() {};
TempClass.prototype = thisArg;
object = new TempClass;

object[symbol];
eval(...);
JasonRammoray commented 6 years ago

Not sure though how inheritance helps to resolve a following case:

var obj = {
    prop: 'value'
};

// Freeze the object by some way

function some (param) {
    return this === obj && param === 42;
}

/*
 * In that case this will point to an object inheriting from obj, but
 * that is not something we need
 */
some.call(obj, 42);