ES6构造函数返回基类实例吗?

8
派生类的构造函数返回基类的实例。
以下代码解释了我的问题:
// Vector is defined by an external module (Unreal.js)
class TestB extends Vector {
    constructor() {
        super();
    }
    Log() {
        console.log("" + this);
    }
}
console.log(new TestB() instanceof TestB) // returns false !!! why ??? 
console.log(new TestB() instanceof Vector) // returns true...

class TestA extends Array {
    constructor() {
        super();
    }
    Log() {
        console.log("" + this);
    }
}
console.log(new TestA() instanceof TestA); // returns true, all is good

这怎么可能实现呢?

2
对我来说,console.log(new TestB() instanceof TestB) 返回 true。 - shilch
是的,它只出现在我的项目中,与这个“Vector”对象有关。我想知道是什么使得这个对象无法派生。 - arthur.sw
1
展示一下 Vector 类。 - shilch
1
https://github.com/ncsoft/Unreal.js/ 是你所指的虚幻引擎吗? - shilch
2
如果函数返回任何对象,new 将使用该对象并丢弃它创建的实例。 - Jonathan Lonowski
显示剩余5条评论
2个回答

10

看起来 Vector 的实现方式使其与 class 不兼容。

以下是 Vector 可能采用的一种方式:

function Vector() {
  var v = Object.create(Vector.prototype);
  return v;
}

class TestB extends Vector {
  constructor() {
    super();
  }
}

console.log(new TestB() instanceof TestB);  // false
console.log(new TestB() instanceof Vector); // true

关键在于,由于Vector返回的对象与new创建的对象不同,因此它的类型是错误的。有关构造函数相对较少知道的一件事是,如果它们返回一个非null的对象引用,则new Constructor的结果是构造函数返回的对象,而不是new创建的对象。

对于那些浏览器支持class的人,这里有一段代码片段:

function Vector() {
  var v = Object.create(Vector.prototype);
  return v;
}

class TestB extends Vector {
  constructor() {
    super();
  }
}

console.log(new TestB() instanceof TestB); // false
console.log(new TestB() instanceof Vector); // true

针对那些浏览器无法使用的用户,可以在Babel REPL上查看实时代码。

令我惊讶的是,使用class Vector并从constructor返回值,Babel和Chrome都能实现这一操作;根据规范是否有效,我还没有找出(尚未)。

class Vector {
  constructor() {
    var v = Object.create(Vector.prototype);
    return v;
  }
}

class TestB extends Vector {
  constructor() {
    super();
  }
}

console.log(new TestB() instanceof TestB); // false
console.log(new TestB() instanceof Vector); // true

为了解决这个问题,您可能需要使用每个实例的hack方法,例如将TestB.prototype的所有方法复制到该实例上。理想情况下,不要使用继承,而是通过聚合(例如,通过在类的实例中拥有一个Vector实例作为属性)来使用Vector,因为它没有为继承设置。

“通过聚合而非继承”这个模式是指什么?你是指通过为每个实例(或者Vector原型本身)添加额外的属性来扩展吗?(很好的回答,我只是从未听说过在这个上下文中使用“聚合”这个词。) - apsillers
@apsillers:另一个术语是“组合”,例如将Vector实例作为属性,而不是继承它。 - T.J. Crowder
2
啊哈,所以使用“有一个”关系,而不是“是一个”关系。 - apsillers

1

我不知道这个问题的确切原因,但是黑客攻击proto解决了这个问题。 :)

class TestB extends Vector {
    constructor() {
        super();
        this.__proto__ = TestB.prototype;
    }
    Log() {
        console.log("" + this);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接