Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeError when assigning shallowly cloned object with a method that calls super

I'm testing the following code in Chrome Canary 63 and on Chrome 61. The goal of the code is to set a method that calls super onto a class instance (z). In my codebase sometimes property blocks are cloned with Object.assign before being added to the instance and whenever this happens the code fails.

I've reproduced the problem with the code example below. The code works fine if avoid the shallow clone (props = Object.assign({}, props);) but if I add that line I get TypeError: (intermediate value).bar is not a function.

I've tried doing Object.create(this, Object.getOwnPropertyDescriptors(props)) instead of Object.assign but it results in the same error.

Is there any way to properly set super on objects that have been cloned?

let Moo = class {
    bar() {
        return " [bar on Moo] ";
    }
};

let Zoo = class extends Moo { 
    bar() { 
        return " [bar on Zoo] " + super.bar();
    }
};

function addProps(inst, props) {
    // Code works if the line below is commented out but otherwise
    // results in TypeError: (intermediate value).bar is not a function
    props = Object.assign({}, props); // <-- Offending code

    Object.setPrototypeOf(props, inst.__proto__);
    Object.assign(inst, props);
}

let props = {
    onZooInst: {
        bar() {
            return " [bar on overridden instance] " + super.bar();
        }
    }
};

let z = new Zoo();
addProps(z, props.onZooInst);
console.log(z.bar());
like image 404
Jarym Avatar asked Oct 18 '22 05:10

Jarym


1 Answers

Is there any way to properly set super on objects that have been cloned?

Nope. super uses the function's [[HomeObject]] slot, which is set when the function (method) is created and cannot be changed at present.

Probably the best quote from the spec on this is in Table 27:

[[HomeObject]]: If the function uses super, this is the object whose [[GetPrototypeOf]] provides the object where super property lookups begin.

The only thing you could do is try to change the prototype of the object that the function's [[HomeObject]] refers to, but that A) Gets ugly fast, and B) Kills performance (in those situations where it matters).

If you're doing lots of "method" cloning, you're better off using simple properties that refer to functions, not methods, and not using super.

like image 93
T.J. Crowder Avatar answered Oct 21 '22 04:10

T.J. Crowder