代理的 JS 子类为实例分配了错误的原型

问题描述 投票:0回答:1

一些我不明白的有趣案例。 我代理类并从代理基类扩展子类。

当由于某种原因在

construct
陷阱内构造子类时,错误的原型会被分配给实例 - 基类的原型而不是子类的原型:

class prototype: Child [
  "constructor",
  "method",
  "childMethod"
]
assigned prototype: Base [
  "constructor",
  "method"
]

Chrome 和 Firefox 中都会发生这种情况。所以它看起来不像是一个错误,而是一切都符合规范。这个问题我不明白为什么。解决方法是手动设置原型(注释行),但谜团仍然存在。

谁能解释一下为什么会发生这种情况:

const proxy = what => new Proxy(what, {

    construct(_class, args, constructor) {

        const obj = new _class(...args);
        
        console.log('class prototype:', _class.name, Object.getOwnPropertyNames(_class.prototype));
        console.log('assigned prototype:', obj.__proto__.constructor.name, Object.getOwnPropertyNames(obj.__proto__));
        
        // for some reason we need this if a class is proxied
        //Object.setPrototypeOf(obj, _class.prototype);

        return obj;
    }
});

const Base = proxy(class Base {
    isBase = true;
    method(){
      console.log('Base method');
    }
});

const Child = proxy(class Child extends Base { // extends from a proxy

    isChild = true;
    method() {
        console.log('Child method');
        super.method();
    }
    childMethod(){}

});

const base = new Base;
const child = new Child;

console.log('--------- EXECUTING METHODS ---------');
base.method();
child.method();

如果我们手动设置原型,一切都会正常:

const proxy = what => new Proxy(what, {

    construct(_class, args, constructor) {

        const obj = new _class(...args);
        
        // for some reason we need this if a class is proxied
        Object.setPrototypeOf(obj, _class.prototype);

        return obj;
    }
});

const Base = proxy(class Base {
    isBase = true;
    method(){
      console.log('Base method');
    }
});

const Child = proxy(class Child extends Base { // extends from a proxy

    isChild = true;
    method() {
        console.log('Child method');
        super.method();
    }
    childMethod(){}

});

const base = new Base;
const child = new Child;

console.log('--------- EXECUTING METHODS ---------');
base.method();
child.method();

javascript es6-class es6-proxy
1个回答
0
投票
预计

super()
this
设置为调用它的原始(顶级)构造函数的实例,但这在您的场景中不会发生。如果在
Child
的构造函数中执行以下操作:

constructor() {
    super();
    console.log(this instanceof Child);
}

您将得到输出

false
。发生这种情况是因为
Base
构造函数的代理由
super()
调用,并且它显式返回
Base
的实例,而没有任何线索表明这实际上是一个
Child
实例。

正如评论中已经解释的那样,super()的原始

意图
的正确执行是将
Reflect.construct
与代理处理程序中的第三个参数一起使用。该处理程序获得第三个参数,告诉您构造实例的预期类型是什么:

    construct(_class, args, constructor) {
        return Reflect.construct(_class, args, constructor);
    }

现在

super()
调用将使用返回的
Child
实例并将
this
设置为它。

© www.soinside.com 2019 - 2024. All rights reserved.