Javascript 使用调用super的方法分配浅克隆对象时出现TypeError
我正在ChromeCanary63和Chrome61上测试以下代码。代码的目标是设置一个方法,该方法对类实例(Javascript 使用调用super的方法分配浅克隆对象时出现TypeError,javascript,ecmascript-6,Javascript,Ecmascript 6,我正在ChromeCanary63和Chrome61上测试以下代码。代码的目标是设置一个方法,该方法对类实例(z)调用super。在我的代码库中,有时属性块在添加到实例之前会使用Object.assign进行克隆,每当发生这种情况时,代码都会失败 我用下面的代码示例再现了这个问题。如果避免浅克隆(props=Object.assign({},props);),代码工作正常,但如果添加该行,则会得到TypeError:(中间值).bar不是函数 我尝试过使用Object.create(这个,Obj
z
)调用super。在我的代码库中,有时属性块在添加到实例之前会使用Object.assign进行克隆,每当发生这种情况时,代码都会失败
我用下面的代码示例再现了这个问题。如果避免浅克隆(props=Object.assign({},props);
),代码工作正常,但如果添加该行,则会得到TypeError:(中间值).bar不是函数
我尝试过使用Object.create(这个,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());
让Moo=class{
bar(){
返回“[bar on Moo]”;
}
};
让Zoo=class扩展Moo{
bar(){
返回“[bar on Zoo]”+super.bar();
}
};
功能添加道具(安装、道具){
//如果下面的行被注释掉,则代码可以工作,否则
//导致TypeError:(中间值).bar不是函数
props=Object.assign({},props);//
有没有办法在已克隆的对象上正确设置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());
不。super
使用函数的[[HomeObject]]
插槽,该插槽在创建函数(方法)时设置,目前无法更改
关于这一点,规范中最好的引用可能是:
[[HomeObject]]
:如果函数使用super
,则该对象的[[GetPrototypeOf]]提供了开始查找super
属性的对象
您唯一能做的就是尝试更改函数的[[HomeObject]]
引用的对象的原型,但A)变得丑陋快速,B)破坏性能(在重要的情况下)
如果您正在进行大量的“方法”克隆,最好使用引用函数而不是方法的简单属性,并且不要使用super
如果正确解释需求,您可以在props
对象中将bar
函数调整为this.bar()
并使用function.prototype.call()
,Function.prototype.apply()
或Reflect.apply()
将此函数调用设置为props.onZooInst.bar
到Moo.prototype
让Moo=class{
bar(){
返回“[bar on Moo]”;
}
};
让Zoo=class扩展Moo{
bar(){
返回“[bar on Zoo]”+super.bar();
}
};
让道具={
onZooInst:{
bar(){
返回“[bar on overrided instance]”+this.bar();
}
}
};
设z=新动物园();
让reflectBar=Reflect.apply(props.onZooInst.bar,z.uu proto_uu,[]);
让callBar=props.onZooInst.bar.call(z.\uuuu proto\uuuu);
console.log(反射条);
console.log(callBar);
对于可能面临相同问题的任何人,我终于找到了解决方案
而不是像这样定义对象文本块
let a = {
someFunc() {
super.someFunc();
}
}
可以使用返回它们的箭头函数替换它们:
let a = () => {
return {
someFunc() {
super.someFunc();
}
}
};
这是因为a();
?为什么要使用class
表达式来定义Moo
和Zoo
?我正在使用ES6语法,super.bar()的目的是调用原型链中的下一个方法。返回“[bar on overrided instance]”+super.bar();
”[bar on overrided instance][bar on Moo]的预期结果是什么 "
?如果super是动态的就好了!我将你的问题添加到这个ESDiscussion线程中:谢谢你的解释-但是为什么没有Object.assign,代码就可以工作?我的尝试基于MDN文档,但根据你的解释,它似乎没有给出完整的细节。好吧,我明白了:Object.assign没有复制方法,我t创建对它们的引用。正如您正确指出的,[[HomeObject]]设置在创建函数的位置。因此,如果我使用Object.setPrototypeOf,它对函数引用没有影响。解决方法之一是计算function.toString以创建新函数,将其放入对象中,然后对其调用setPrototypeOf,但这有点太粗糙,没有用处,并且它会在原始函数上闪现任何作用域。@Jarym:NJavaScript复制函数(除了使用通常不起作用的toString
和eval
)时,您总是在处理引用(与其他对象一样)。var f1=function(){};
在f1
中存储对函数的引用var f2=f1;
(这基本上就是对象.assign
所做的)将引用复制到f2
对象。setPrototypeOf
确实会改变条,如果应用到正确的对象(),它会被调用,但正如我所说的,它会很快变丑并破坏对象的性能。:-)谢谢,我知道我可以用不同的方式重写代码,但我想做得更好。我不得不承认目前不可能做到这一点。你是否仍在使用相同的addProps
函数和你新的箭头函数方法?你能发布完整的代码作为你的答案吗?