PaperJS has many static constructors (like Rectangle) on their base constructor functions such as Shape. I'd like to extend one of those static constructors like this,
class Rect extends paper.Shape.Rectangle {
constructor() {
super(...arguments);
}
customMethod() {}
}
const A = new Rect();
But what I get in variable A is an instance of class "Shape" which doesn't have the "customMethod".
What is a solution?
Paper.js don't seem to use standard ecmascript
classes; their class system is based on
straps.js.
You can see it in action
in the source code of Rectangle.js,
that is the class available as paper.Rectangle.
If you wanted to extend Rectangle, you could
use its method .extend, like this:
const Rect = paper.Rectangle.extend({
customMove(dx, dy){
this.x += dx;
this.y += dy;
}
});
const rect = new Rect(10, 10, 100, 100);
rect.customMove(30, 10);
As for Shape.Rectangle it can't
be properly extended, since it is just
a method of the class Shape - see
the source code.
You could extend Shape itself to add a new static
method:
const Shape1 = paper.Shape.extend({
statics:{
Rect(){
//... access to this.Rectangle
}
}
});
And in some cases, it is feasible to just add
a new method directly to Shape:
paper.Shape.Rect = function(){
//... access this.Rectangle, or paper.Shape.Rectangle)
}
Related
basic question: why is the constructor needed in class?
Below is a simple test:
Circle class with a constructor function
Circle2 class without a constructor function.
... However, both classes work and an instance can be created.
Going back to the topic, why is the constructor needed in class?
class Circle {
draw() {
console.log('hello');
}
}
c = new Circle(1);
class Circle2 {
constructor(radius) {
this.radius = radius;
}
draw() {
console.log('hello');
}
}
c2 = new Circle2(1);
if you do c.radius, it has not been defined, but c2.radius will be
When you dont have the constructor, your class will take in arguments but wont do anything with them
When no constructor is declared, the new operator only creates an empty object with Circle.prototype as prototype. If you want to initialize some properties of the class instance, then you need a constructor.
You have another alternative, if the property you want to create doesn't depend on the constructor parameters, then you can use class fields as an equivalent:
class Foo {
// this is equivalent to a constructor initialization but it only takes a static assignment
bar = 'bar';
}
Class fields adds properties on the class instance just like a constructor does.
It appears to be common practice to inherit from the EventEmitter if you want your class to support events.
For example Google does it for Puppeteer, the WebSocket module does it, mongoose does it, ... just to name a few.
But is this really good practice? I mean sure it looks nice and clean, but from an OOP perspective it seems wrong. For example:
const EventEmitter = require('events')
class Rectangle extends EventEmitter {
constructor(x,y,w,h) {
super()
this.position = {x:x, y:y}
this.dimensions = {w:w, h:h}
}
setDimensions(w,h) {
this.dimensions = {w:w, h:h}
this.emit('dimensionsChanged')
}
}
would make it seem like Rectangle is an EventEmitter at its core even though the eventing functionality is secondary.
What if you decide that Rectangle now needs to inherit from a new class called Shape?
class Shape {
constructor(x,y) {
this.position = {x:x, y:y}
}
}
class Rectangle extends Shape {
constructor(x,y,w,h) {
super(x,y)
this.dimensions = {w:w, h:h}
}
}
Now you would have to make Shape inherit from the EventEmitter. Even if only one class inheriting from Shape actually needs eventing.
Wouldn't something like this make way more sense?
class Shape {
constructor(x,y) {
this.position = {x, y}
}
}
const EventEmitter = require('events')
class Rectangle extends Shape {
constructor(x,y,w,h) {
super(x,y)
this.dimensions = {w, h}
this.em = new EventEmitter()
}
setDimensions(w,h) {
this.dimensions = {w:w, h:h}
this.em.emit('dimensionsChanged')
}
}
const rectangle = new Rectangle(1,2,3,4)
rectangle.em.on('dimensionsChanged', ()=>{console.log('dimensions changed')})
rectangle.setDimensions(10,20)
Yes, it absolutely makes more sense.
Inheritance should be used to denote is a relationships: class Rectangle extends Shape is ok since Rectangle is a shape, but here the rectangle itself is not an EventEmitter.
Instead, we have an can relationship: Rectangle can emit an event, and that is exactly where you should favor composition over inheritance, which is what happens in your last code snippet.
We can only speculate as to why some famous libs don't do that - retro-compatibility, simplicity of APIs, or simply bad design.
I wrote some code:
class Base {
// Default value
myColor = 'blue';
constructor() {
console.log(this.myColor);
}
}
class Derived extends Base {
myColor = 'red';
}
// Prints "blue", expected "red"
const x = new Derived();
I was expecting my derived class field initializer to run before the base class constructor.
Instead, the derived class doesn't change the myColor property until after the base class constructor runs, so I observe the wrong values in the constructor.
Is this a bug? What's wrong? Why does this happen? What should I do instead?
Not a Bug
First up, this is not a bug in TypeScript, Babel, or your JS runtime.
Why It Has To Be This Way
The first follow-up you might have is "Why not do this correctly!?!?". Let's examine the specific case of TypeScript emit. The actual answer depends on what version of ECMAScript we're emitting class code for.
Downlevel emit: ES3/ES5
Let's examine the code emitted by TypeScript for ES3 or ES5. I've simplified + annotated this a bit for readability:
var Base = (function () {
function Base() {
// BASE CLASS PROPERTY INITIALIZERS
this.myColor = 'blue';
console.log(this.myColor);
}
return Base;
}());
var Derived = (function (_super) {
__extends(Derived, _super);
function Derived() {
// RUN THE BASE CLASS CTOR
_super();
// DERIVED CLASS PROPERTY INITIALIZERS
this.myColor = 'red';
// Code in the derived class ctor body would appear here
}
return Derived;
}(Base));
The base class emit is uncontroversially correct - the fields are initialized, then the constructor body runs. You certainly wouldn't want the opposite - initializing the fields before running the constructor body would mean you couldn't see the field values until after the constructor, which is not what anyone wants.
Is the derived class emit correct?
No, you should swap the order
Many people would argue that the derived class emit should look like this:
// DERIVED CLASS PROPERTY INITIALIZERS
this.myColor = 'red';
// RUN THE BASE CLASS CTOR
_super();
This is super wrong for any number of reasons:
It has no corresponding behavior in ES6 (see next section)
The value 'red' for myColor will be immediately overwritten by the base class value 'blue'
The derived class field initializer might invoke base class methods which depend on base class initializations.
On that last point, consider this code:
class Base {
thing = 'ok';
getThing() { return this.thing; }
}
class Derived extends Base {
something = this.getThing();
}
If the derived class initializers ran before the base class initializers, Derived#something would always be undefined, when clearly it should be 'ok'.
No, you should use a time machine
Many other people would argue that a nebulous something else should be done so that Base knows that Derived has a field initializer.
You can write example solutions that depend on knowing the entire universe of code to be run. But TypeScript / Babel / etc cannot guarantee that this exists. For example, Base can be in a separate file where we can't see its implementation.
Downlevel emit: ES6
If you didn't already know this, it's time to learn: classes are not a TypeScript feature. They're part of ES6 and have defined semantics. But ES6 classes don't support field initializers, so they get transformed to ES6-compatible code. It looks like this:
class Base {
constructor() {
// Default value
this.myColor = 'blue';
console.log(this.myColor);
}
}
class Derived extends Base {
constructor() {
super(...arguments);
this.myColor = 'red';
}
}
Instead of
super(...arguments);
this.myColor = 'red';
Should we have this?
this.myColor = 'red';
super(...arguments);
No, because it doesn't work. It's illegal to refer to this before invoking super in a derived class. It simply cannot work this way.
ES7+: Public Fields
The TC39 committee that controls JavaScript is investigating adding field initializers to a future version of the language.
You can read about it on GitHub or read the specific issue about initialization order.
OOP refresher: Virtual Behavior from Constructors
All OOP languages have a general guideline, some enforced explicitly, some implicitly by convention:
Do not call virtual methods from the constructor
Examples:
C# Virtual member call in a constructor
C++ Calling virtual functions inside constructors
Python Calling member functions from a constructor
Java Is it OK to call abstract method from constructor in Java?
In JavaScript, we have to expand this rule a little
Do not observe virtual behavior from the constructor
and
Class property initialization counts as virtual
Solutions
The standard solution is to transform the field initialization to a constructor parameter:
class Base {
myColor: string;
constructor(color: string = "blue") {
this.myColor = color;
console.log(this.myColor);
}
}
class Derived extends Base {
constructor() {
super("red");
}
}
// Prints "red" as expected
const x = new Derived();
You can also use an init pattern, though you need to be cautious to not observe virtual behavior from it and to not do things in the derived init method that require a complete initialization of the base class:
class Base {
myColor: string;
constructor() {
this.init();
console.log(this.myColor);
}
init() {
this.myColor = "blue";
}
}
class Derived extends Base {
init() {
super.init();
this.myColor = "red";
}
}
// Prints "red" as expected
const x = new Derived();
I would respectfully argue this is, in fact, a bug
By doing an unexpected thing, this is undesired behavior that breaks common class extension use cases. Here is the initialization order that would support your use case and that I would argue is better:
Base property initializers
Derived property initializers
Base constructor
Derived constructor
Problems / Solutions
- The typescript compiler currently emits property initializations in the constructor
The solution here is to separate the property initializations from the calling of the constructor functions. C# does this, although it inits base properties after derived properties, which is also counterintuitive. This could be accomplished by emitting helper classes so that the derived class can initialize the base class in an arbitrary order.
class _Base {
ctor() {
console.log('base ctor color: ', this.myColor);
}
initProps() {
this.myColor = 'blue';
}
}
class _Derived extends _Base {
constructor() {
super();
}
ctor() {
super.ctor();
console.log('derived ctor color: ', this.myColor);
}
initProps() {
super.initProps();
this.myColor = 'red';
}
}
class Base {
constructor() {
const _class = new _Base();
_class.initProps();
_class.ctor();
return _class;
}
}
class Derived {
constructor() {
const _class = new _Derived();
_class.initProps();
_class.ctor();
return _class;
}
}
// Prints:
// "base ctor color: red"
// "derived ctor color: red"
const d = new Derived();
- Won't the base constructor break because we're using derived class properties?
Any logic that breaks in the base constructor can be moved to a method that would be overridden in the derived class. Since derived methods are initialized before the base constructor is called, this would work correctly. Example:
class Base {
protected numThings = 5;
constructor() {
console.log('math result: ', this.doMath())
}
protected doMath() {
return 10/this.numThings;
}
}
class Derived extends Base {
// Overrides. Would cause divide by 0 in base if we weren't overriding doMath
protected numThings = 0;
protected doMath() {
return 100 + this.numThings;
}
}
// Should print "math result: 100"
const x = new Derived();
Say there is a parent class Shape and a child class Rectangle. I want to reuse a parent class property's value from within the child class.
Can I do this without re-initializing it in the child class (using call or apply)?
I want all the child objects to use the same parent property value.
//Parent
function Shape(ctx) {
this.context = ctx;
}
Shape.prototype.getContext = function() { return this.context; };
//Child - rectangle inherits from shape
function Rectangle(x,y,w,h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
//setup inheritance
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
Rectangle.prototype.draw = function() {
//want to use inherited context here
return this.context;
}
//create and run
var shape = new Shape("value");
var rectangle = new Rectangle(0,0,100,100);
//returns "value"
console.log( shape.getContext() );
//returns undefined - needing "value"
console.log( rectangle.draw() );
EDIT - After the responses below I think this is what I need. Since the rectangle instance is not inheriting from the shape instance the "value" assigned to shape is not being passed to rectangle. How about assigning it as the default inside Shape and then calling the Shape constructor inside the Rectangle constructor. This allows me to share the same context value to all the child objects right?
Side issue, the setter doesn't affect Shape children. So I'm working on that.
//Parent
function Shape() {
this.context = "value";
}
Shape.prototype.getContext = function() { return this.context; };
Shape.prototype.setContext = function(x) { this.context = x; };
//Child - rectangle inherits from shape
function Rectangle(x,y,w,h) {
Shape.call(this);
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
//setup inheritance
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
Rectangle.prototype.draw = function() {
//want to use inherited context here
return this.context;
}
//create and run
var rectangle = new Rectangle(0,0,100,100);
//returns "value"
console.log( rectangle.draw() );
EDIT - Thanks to the responses, I think below is accomplishing what I was initially trying to do. The Shape parent begins with a default context value. The Shape constructor now also accepts an argument in case child classes want to change it when initially called. Each child class then has a getter and setter as well for the context, but it will always default to the initial Parent value unless changed. After looking into it more the Shape is starting to feel like an abstract class or an interface, but that has nothing to do with what I was initially asking.
//Parent
function Shape(ctx) {
this.context = (typeof ctx === "undefined") ? "default" : ctx;
}
Shape.prototype.getContext = function() { return this.context; };
Shape.prototype.setContext = function(x) { this.context = x; };
//Child - rectangle inherits from shape
function Rectangle(x,y,w,h) {
//calls parent constructor
Shape.call(this);
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
//setup inheritance
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
//getter and setter - context defaults to parent value, but can be changed
Rectangle.prototype.getContext = function() { return this.context; };
Rectangle.prototype.setContext = function(x) { this.context = x; };
//other rectangle methods
Rectangle.prototype.draw = function() {
return "doing something with " + this.context;
}
//create and run
var rectangle = new Rectangle(0,0,100,100);
//starts with Parent "default"
console.log( rectangle.getContext() );
//changes and uses different context
rectangle.setContext("different context");
console.log( rectangle.draw() );
Can I do this without re-initializing it in the child class (using call or apply)?
No, there's no way around calling your super constructor.
Notice that this is not re-initialising the property, the call is creating and initialising the property at all.
I want to reuse a parent class property's value from within the child class.
This doesn't really make sense. The property is part of the instance, not of the class. There is no instance of the parent class if you have multiple children, there are just child instances. If you are really creating an instance of the parent class (like in your example code), then that is a separate object and has nothing to do with the other instances - mostly, the children objects are not in any way derived from that parent instance.
The return value is undefined when you do this to setup your rectangle:
//create and run
var shape = new Shape("value");
var rectangle = new Rectangle(0,0,100,100);
because you are actually not connecting that shape to rectangle. You have merely made two separate instances of Shape and Rectangle which aside from sharing certain structures have nothing to do with each other.
There are possible scenarios to fixing this. Create a new Shape to seed the value with up front when defining the prototype.
//Use predefined Shape
var shape = new Shape("value");
Rectangle.prototype = shape;
Now when the previously shown call to draw is used, value will be returned and logged to the console.
This is not a complete scenario in my opinion though because while you have defined a getter for the context, there may be scenarios where you wish to change that. I would also suggest implementing a setter for the context so that you can inject different ones if you feel like it.
I'm working on a chess game built in JavaScript. I'm taking an object-oriented approach to it and am having some difficulty working with JavaScript's inheritance. I want there to be a "Piece" abstract class that holds some fields and basic getters/setters such as is this piece black or white. I then want to have classes for each type of piece that I can instantiate like so:
var pieceOne = new Pawn();
The Pawn() should have all the fields and methods of Piece but have its own method for movement, and additional fields (such as whether or not it has moved yet, as this doesn't matter for most pieces). Here's my current Piece class:
//This object specifies basic information about pieces.
"use strict";
function Piece(color, type, captured, hasMoved) {
this.color = color;
this.type = type;
this.captured = captured;
this.hasMoved = hasMoved;
this.image = color + "_" + type + ".svg";
}
Piece.prototype.getImage = function getImage(){
return this.image;
}
Piece.prototype.isCaptured = function isCaptured(){
return this.captured;
};
I know if I am going to make a subclass for every kind of piece that I'd probably eliminate the "type" field, but how could I make a Pawn subclass? Something like this?
function Pawn() = new Piece(color, captured, hasMoved);
Pawn.prototype.getLegalMoves = function getLegalMoves(){
//return legal moves
}
var pieceOne = new Pawn("black", false, false);
Extending a class can be done in different ways. The simplest method to extend an class is to use Object.create method. This is common method which is used to achieve abstraction (Link to my blog). Let's give an example of the Object.create method as follows.
var Logger = { log : function(log){} }
var ConsoleLogger = function() {};
ConsoleLogger.prototype = Object.create(Logger);
If you are willing to take an object oriented approach on JS I would recommend you to follow the power constructor pattern.
Basically you have a function that creates objects for you and take advantage of the closures to hide the internal properties (fields or methods).
function myObject(){
var that={};
var myPrivateField;
var myPrivateFunction=function(){
}
that.myPublicMethod=function(){
}
return that;
}
Then you can just call the method myObject() and you will get a new object of this type.
You can extend this example to use inheritance by just calling the power constructor of another object and then use object augmentation. Take a look at the example of parasatic inheritance of Douglas Crockford.
You can call Piece's constructor from Pawn and have that constructor operate on the Pawn instance:
function Pawn(/* args... */) {
Piece.call(this, color, type, captured, hasMoved);
/* Pawn-specific constructor code... */
}
I believe it's just a matter of setting the prototype of the specific piece constructors to an instance of Piece. For example:
Pawn.prototype = new Piece("", false, false);
However, this will not call the Piece (super) constructor every time you instantiate a new Pawn, so you'll have to manually assign color, type, etc. from the Pawn constructor:
-- EDIT --
You might prefer this instead: Javascript inheritance: call super-constructor or use prototype chain?
Take a look at this: https://github.com/haroldiedema/joii
var BaseClass = function()
{
this.some_var = "foobar";
/**
* #return string
*/
this.someMethod = function() {
return this.some_var;
}
};
var MyClass = new Class({ extends: BaseClass }, function()
{
/**
* #param string value
*/
this.__construct = function(value)
{
this.some_var = value;
}
})
Usage:
var obj = new MyClass("Hello World!");
console.log( obj.someMethod() ); // Hello World!