使用调用super的方法分配浅克隆对象时的TypeError

时间:2017-09-19 17:34:04

标签: javascript ecmascript-6

我正在Chrome Canary 63和Chrome 61上测试以下代码。代码的目标是设置一个调用super到类实例(z)的方法。在我的代码库中,有时属性块会在添加到实例之前使用Object.assign进行克隆,并且只要发生这种情况,代码就会失败。

我用下面的代码示例重现了这个问题。如果避免浅层克隆(props = Object.assign({}, props);),代码工作正常,但如果我添加该行,我会得到TypeError: (intermediate value).bar is not a function

我尝试过Object.create(this, Object.getOwnPropertyDescriptors(props))代替Object.assign,但会导致同样的错误。

有没有办法在已克隆的对象上正确设置super

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());

3 个答案:

答案 0 :(得分:3)

  

有没有办法在已克隆的对象上正确设置super

不。 super使用函数的[[HomeObject]]插槽,该插槽在创建函数(方法)时设置,目前无法更改。

关于此规范的最佳引用可能是Table 27

  

[[HomeObject]]:如果函数使用super,则[[GetPrototypeOf]]提供super属性查找开始的对象的对象。

你唯一能做的就是尝试改变函数[[HomeObject]]引用的对象的原型,但是A)变得丑陋 ,和B)杀死表现(在重要的情况下)。

如果您正在做很多&#34;方法&#34;克隆,您最好使用引用函数的简单属性,而不是方法,而不是使用super

答案 1 :(得分:0)

如果正确解释要求,您可以将props对象的this.bar()功能调整为Function.prototype.call()并使用Function.prototype.apply()Reflect.apply()this进行设置对props.onZooInst.bar Moo.prototype

let Moo = class { bar() { return " [bar on Moo] "; } }; let Zoo = class extends Moo { bar() { return " [bar on Zoo] " + super.bar(); } }; let props = { onZooInst: { bar() { return " [bar on overridden instance] " + this.bar(); } } }; let z = new Zoo(); let reflectBar = Reflect.apply(props.onZooInst.bar, z.__proto__, []); let callBar = props.onZooInst.bar.call(z.__proto__); console.log(reflectBar); console.log(callBar);函数调用Properties

&#13;
&#13;
Description
&#13;
&#13;
&#13;

答案 2 :(得分:0)

对于任何可能遇到同样问题的人,我终于找到了解决方案。

而不是像

那样定义对象文字的块
let a = {
    someFunc() {
        super.someFunc();
    } 
}

您可以使用返回它们的箭头函数替换它们:

let a = () => {
    return {
        someFunc() {
            super.someFunc();
        } 
    }
};

这是有效的,因为a().someFunc !== a().someFunc - 换句话说,你得到了一个新功能,而我们需要解决动态代码生成(eval / new Function)。您应该能够安全地对Object.setPrototypeOf的返回值a()执行。