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.
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?
Yes, it is possible, when your constructor function executes, the this value has already the [[Prototype]] internal property pointing to the ValidateFields.
Initializing Objects in ConstructorYou can call other class methods from the constructor because the object is already initialized. The constructor also creates an object whose properties have their default values — either empty ( [] ) or the default value specified in the property definition block.
Invoking a constructor from a method No, you cannot call a constructor from a method. The only place from which you can invoke constructors using “this()” or, “super()” is the first line of another constructor. If you try to invoke constructors explicitly elsewhere, a compile time error will be generated.
Removing extends Object
and the super()
call seems to work for me.
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. extends Object
is implicit, so remove it.
It seems that the handling of extends Object
is a bug in 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
But it looks like Babel's transpiled es5 is broken.
To somewhat explain this behavior, let's take a look at the transpiled es5 from babel.
Given this 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. 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. It basically says "The super-class has methods defined, so let's look there for methods (like assign
)". There's no sense in adding Object
itself to that hierarchy since any object in Javascript will inherit methods from Object
anyway.
By stepping through the transpiled code, _possibleConstructorReturn(OtherClassExtender, OtherClass)
says typeof call
is undefined
so it returns OtherClassExtender
.
_possibleConstructorReturn(ObjectExtender, Object)
says typeof call
is object
so it returns Object
.
Object instances don't have an assign
method. assign
is a class method on the Object
class, it doesn't exist on (new Object).assign
for example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With