如何从JS类的构造函数调用函数

use*_*965 5 javascript reactjs webpack

我正在创建一个矩阵类(将在react应用中使用),我想以此方式定义它:

class Matrix extends Object {
    constructor(r, c) {
        super();
        this.rows = new Array(r);
        for (var i=0; i<r; i++) {
            this.rows[i] = new Array(c);
        }
        this.assign((v,i,j) => (i===j)? 1:0);   // ERROR HERE
    }
    assign(f) {
        for (var i=0; i<this.rows.length; i++) {
            for (var j=0; j<this.rows[i].length; j++) {
                this.rows[i][j] = f(this.rows[i][j], i, j);
            }
        }
    }
    // and so on
Run Code Online (Sandbox Code Playgroud)

这可以通过webpack编译,但是在运行时,我在chrome控制台中收到一个错误,提示_this.assign不是function

我可以这样工作:

constructor(r, c) {
    super();
    this.rows = new Array(r);
    for (var i=0; i<r; i++) {
        this.rows[i] = new Array(c);
    }
    this.assign = function(f) {
        for (var i=0; i<r; i++) {
            for (var j=0; j<r; j++) {
                this.rows[i][j] = f(this.rows[i][j], i, j);
            }
        }
    };
    this.assign((v,i,j) => (i===j)? 1:0);
}
Run Code Online (Sandbox Code Playgroud)

但这是错误的,对吧?我不必在构造函数中定义对象的所有功能,对吗?在同一个文件中,我定义了React类,例如:

class MatrixComponent extends React.Component { ... }
Run Code Online (Sandbox Code Playgroud)

并且那些能够调用函数而无需在构造函数中定义它们的函数。我想念什么?

Fra*_*bot 5

删除extends Objectsuper()通话似乎对我有用。

class Matrix { // extends Object {
    constructor(r, c) {
        // super();
        this.assign();
    }
    assign() {
    }
}
Run Code Online (Sandbox Code Playgroud)

每个类的原型链中都已经有 Object,因此您不会通过扩展 Object 获得任何东西。extends Object是隐式的,所以删除它。


看来extends Object是Babel 中的一个bug的处理。Chromium 浏览器的内置 es6 引擎可以很好地处理代码,因为它已在此处修复:https ://bugs.chromium.org/p/v8/issues/detail?id=3886

但是看起来 Babel 转译的 es5 坏了。

在 Chrome 中使用 es6


为了稍微解释一下这种行为,让我们看一下从 babel 转译过来的 es5。

鉴于此 es6:

class OtherClass {}

class OtherClassExtender extends OtherClass {
    constructor(r, c) {
        super();
        this.assign();
    }
    assign() {
    }
}

class ObjectExtender extends Object {
    constructor(r, c) {
        super();
        this.assign();
    }
    assign() {
    }
}

new OtherClassExtender(1, 2);
new ObjectExtender(1, 2);
Run Code Online (Sandbox Code Playgroud)

我们将只取转译后的 es5 的片段。我已经删除了很多代码。这不是完整的转译源:

function _possibleConstructorReturn(self, call) {
  if (!self) {
    throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
  }
  if (call && (typeof call === "object" || typeof call === "function")) {
    return call;
  } else {
    return self;
  }
}

var OtherClass = function OtherClass() {};

var OtherClassExtender = function (_OtherClass) {    
    function OtherClassExtender(r, c) {
        var _this = _possibleConstructorReturn(this, _OtherClass.call(this));
        _this.assign();
        return _this;
    }
    OtherClassExtender.prototype.assign = function assign() {};
    return OtherClassExtender;
}(OtherClass);

var ObjectExtender = function (_Object) {
    function ObjectExtender(r, c) {
        var _this2 = _possibleConstructorReturn(this, _Object.call(this));
        _this2.assign();
        return _this2;
    }
    ObjectExtender.prototype.assign = function assign() {};
    return ObjectExtender;
}(Object);

new OtherClassExtender(1, 2);
new ObjectExtender(1, 2);
Run Code Online (Sandbox Code Playgroud)

_possibleConstructorReturn基本上是super,其中 Babel 保持类的超类的引用,因此方法调用可以正确地遍历继承层次结构。它基本上是说“超类定义了方法,所以让我们在那里寻找方法(如assign)”。将Object自己添加到该层次结构是没有意义的,因为 Javascript 中的任何对象都会继承方法Object

通过该transpiled代码步进,_possibleConstructorReturn(OtherClassExtender, OtherClass)typeof callundefined这样,它返回OtherClassExtender

_possibleConstructorReturn(ObjectExtender, Object)typeof callobject所以它返回Object

对象实例没有assign方法。assign是类上的类方法,例如Object它不存在(new Object).assign