简体   繁体   English

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

[英]How to call function from the constructor of a JS class

I'm creating a matrix class (to be used in a react app) which I'd like define this way: 我正在创建一个矩阵类(用于反应应用程序),我想用这种方式定义:

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

This compiles okay via webpack, but while running, I get an error in the chrome console saying that _this.assign is not a function . 这可以通过webpack编译好,但是在运行时,我在chrome控制台中收到错误,说_this.assign不是一个函数

I can make it work this way: 我可以这样工作:

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

But that's wrong, right? 但这是错的,对吧? I shouldn't have to define all of an object's functions in the constructor, right? 我不应该在构造函数中定义所有对象的函数,对吧? In the very same file, I define react classes like: 在同一个文件中,我定义了反应类,如:

class MatrixComponent extends React.Component { ... }

and those are able to call functions without defining them in the constructor. 那些能够调用函数而不在构造函数中定义它们。 What am I missing? 我错过了什么?

Removing extends Object and the super() call seems to work for me. 删除extends Objectsuper()调用似乎对我有用。

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

Every class has Object in its prototype chain already, so you don't gain anything by extending Object. 每个类已经在其原型链中具有Object,因此您不会通过扩展Object获得任何东西。 extends Object is implicit, so remove it. extends Object是隐式的,因此将其删除。


It seems that the handling of extends Object is a bug in Babel. 似乎处理extends Object是Babel中的一个错误。 The Chromium browser's built-in es6 engine handles the code just fine, since it was fixed here: https://bugs.chromium.org/p/v8/issues/detail?id=3886 Chromium浏览器的内置es6引擎处理代码很好,因为它已在此修复: https ://bugs.chromium.org/p/v8/issues/detail?id = 3886

But it looks like Babel's transpiled es5 is broken. 但看起来Babel的转换es5已被打破。

在Chrome中使用es6


To somewhat explain this behavior, let's take a look at the transpiled es5 from babel. 为了解释这种行为,让我们看一下来自babel的转换后的es5。

Given this es6: 鉴于此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);

We'll take just a snippet of the transpiled es5. 我们将只收集已转换的es5的片段。 I've removed a lot of code. 我删除了很多代码。 This is not the full transpiled source: 这不是完整的转换来源:

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

_possibleConstructorReturn is basically super , where Babel is keeping a reference of the class' super-class so method calls can properly traverse the inheritance hierarchy. _possibleConstructorReturn基本上是super ,其中Babel保留了类的超类的引用,因此方法调用可以正确地遍历继承层次结构。 It basically says "The super-class has methods defined, so let's look there for methods (like assign )". 它基本上说“超级类已经定义了方法,所以让我们看一下方法(比如assign )”。 There's no sense in adding Object itself to that hierarchy since any object in Javascript will inherit methods from Object anyway. Object本身添加到该层次结构中没有任何意义,因为Javascript中的任何对象都将从Object继承方法。

By stepping through the transpiled code, _possibleConstructorReturn(OtherClassExtender, OtherClass) says typeof call is undefined so it returns OtherClassExtender . 通过逐步执行转换后的代码, _possibleConstructorReturn(OtherClassExtender, OtherClass)表示typeof call undefined因此返回OtherClassExtender

_possibleConstructorReturn(ObjectExtender, Object) says typeof call is object so it returns Object . _possibleConstructorReturn(ObjectExtender, Object)表示typeof callobject因此它返回Object

Object instances don't have an assign method. 对象实例没有assign方法。 assign is a class method on the Object class, it doesn't exist on (new Object).assign for example. assignObject类的一个类方法,它不存在于(new Object).assign例如。

By trial and error, I discovered that extending null vs Object , fixes the problem: 通过反复试验,我发现扩展null vs Object ,修复了问题:

class Matrix extends null { ... }

I guess this is an answer, but I'm mystified about why, and what was wrong with how I was trying to do it. 我想这是一个答案,但我对于为什么以及我试图这样做有什么不对而感到困惑。 I will happily mark correct a better answer than this one: on that really explains how this stuff works. 我很乐意用正确的方式标记一个更好的答案 :这真的解释了这些东西是如何工作的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM