Invoke "superclass" constructor in JavaScript - javascript

I just got into JavaScript and I'm kind of puzzled by its object-oriented behavior.
I was just trying to create a class Point2D with x,y members and extend it with a Point3D class with x,y,z members.
The behavior I'm trying to achieve is something like, let's say it in C#:
class Point2D
{
int x, y;
public Point2D(int x, int y) { this.x = x; this.y = y; }
}
class Point3D : Point2D
{
int z;
public Point3D(int x, int y, int z) : base(x, y) { this.z = z; }
}
I read a lot of stuff but I don't seem to really find what I'm looking for.
Here's what I've come up to so far:
function Point2D(x, y) { this.x = x; this.y = y; }
Point2D.prototype.constructor = Point2D;
function Point3D(x, y, z) { Point2D.prototype.constructor.call(this); this.z = z; }
Point3D.prototype = new A(); // see latter explanation
Point3D.prototype.constructor = B;
var p = new Point3D(10, 20, 30);
Which is obviously wrong.
Now, I know I should do something like Point3D.prototype = new A(x, y) but I don't want to create a prototype with fixed x,y coordinates and variable z.
It must be very simple, but I'm just not getting it, I can't seem to call the superclass constructor or to make it behave properly.

JavaScript's prototypal inheritance provides a couple of different flexible ways to perform the kind of polymorphic constructors you're looking for. In your particular example, you want something like this:
function Point2D(x, y) {
this.x = x;
this.y = y;
}
function Point3D(x, y, z) {
Point2D.call(this, x, y);
this.z = z;
}
Fussing with explicitly setting the constructor on the prototype is not strictly necessary here. (It is really only necessary when you are creating the prototype "all at once" -- e.g., with an object.)
For a detailed discussion of object-oriented JavaScript, I'd recommend Nicholas Zakas' Principles of Object-Oriented Programming in JavaScript (ebook) or the discussion of prototypes and inheritance in his other book, Professional JavaScript for Web Developers.

Related

shorthand way to reference `this` propeties?

I have a class
class Foo {
constructor(x, y) {
this.x = x
this.y = y
Bar() {
console.log(this.x, this.y)
}
I recall seeing a method of referring to this. variables without having to specify this. Something like
class Foo {
constructor(x,y) {
this.x = x
this.y = y
Bar() {
x,y = [this] // something like this
console.log(x, y) // equivalent to this.x, this.y
}
I desire this because I have dozens of statements that call methods on this.ctx - like this.ctx.rect() - and I don't want to have to have this. prepended to all of them for the sake of readability.
Is there a syntax for this?
You can deconstruct this like any JavaScript object,
Bar() {
const {x, y} = this;
}
I do not recommend doing this however, it seems like it would not scale well as a technique.
Objects (including arrays and functions) are handled by reference, meaning that if you write
let a = this.ctx;
then a points to the same object as ctx and you can do a.rect().

In JavaScript, is there a way to write global functions in a static style? (I'm not sure that I worded that correctly)

I know that you can write functions which work if you input different arguments. However, is there a way to add a function which you can write such as
vector.function(arguments);.
When I write the functions, I use the vector or object as an argument to get the value back, but is there a way to write it like I have above?
var Vector = function(x, y) {
this.x = x;
this.y = y;
}
Vector.prototype.yourFunction = function() {
/* access vector properties */
console.log(this.x, this.y);
}
var vector = new Vector(1,2);
vector.yourFunction(); // 1 2
It looks like what you want it an object containing a set of functions inside of it. When functions are defined inside of an objects, these are commonly referred to as "methods". This is a useful way of "namespacing" a set of common methods. You can achieve this in many ways. Here is the most basic way:
const vector = {
x: 0,
y: 0,
getDirection() {
return Math.atan2(this.y, this.x);
},
};
console.log(vector.getDirection());
This will work fine if you only need one vector. If you want to have many vectors, you can use instantiation to create as many vectors as you need. For example:
// Globally defined function
function getDirection(x, y) {
return Math.atan2(y, x);
}
function Vector(x = 0, y = 0) {
this.x = x;
this.y = y;
this.getDirection = () => {
// Defer to the globally defined function
return getDirection(x, y);
};
return this;
}
const vectors = [new Vector(10, 15), new Vector(0, 10), new Vector(10, 50)];
vectors.forEach((vector) => {
console.log(vector.getDirection());
});

JavaScript: Diagram to explain inheritance, __proto__ and prototype

I have the following code:
function Shape(x, y) {
this.x = x;
this.y = y;
}
Shape.prototype.describeLocation = function() {
return 'I am located at ' + this.x + ', ' + this.y;
};
var myShape = new Shape(1, 2);
function Circle(x, y, radius) {
Shape.call(this, x, y); // call parent constructor
this.radius = radius;
}
var myFirstCircle = new Circle(3, 4, 10);
Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.calculateArea = function() {
return 'My area is ' + (Math.PI * this.radius * this.radius);
};
var mySecondCircle = new Circle(3, 4, 10);
I'd like a visual* explanation of:
the changes caused by Circle.prototype = Object.create(Shape.prototype);
the
__proto__ and
prototype
connections between the objects
how mySecondCircle inherits the describeLocation() method from Shape
why the calculateArea() method exists for mySecondCircle but not for myFirstCircle:
> myFirstCircle.calculateArea()
Uncaught TypeError: undefined is not a function
> mySecondCircle.calculateArea()
"My area is 314.1592653589793"
* When trying to understand JavaScript issues regarding inheritance, a diagram really is
worth a thousand words,
and I've found the diagrams in these questions very helpful:
1,
2,
3,
4.
Full-size — image, page.
Circle.prototype (original) is created as a side-effect of function Circle(...) {...}
Circle.prototype (redefined) is created by Circle.prototype = Object.create(Shape.prototype);
I also made this animated version to show the order in which the objects are created:
Full-size — image, page.
why the calculateArea() method exists for mySecondCircle but not for myFirstCircle:
By re assigning the Circle.prototype you are de referencing the proto used by instances already created. Following code demonstrates:
var org = {name:"org"}
var copy1 = org;//copy1===org
org={name:"changed"};org!==copy1
var copy2 = org;//copy2===org
org.name="again";//copy2.name === "again"
When we change org name by assigning a completely different object to org (de referencing it) copy1 and org no longer point to the same object.
When we set the name property of org (mutate org) copy2 and org still point to the same object.

passing parent object automatically

So I have a couple of classes
function BaseClass(x, y){
this.x = x;
this.y = y;
}
function ImageClass(img, w, h, x, y){
BaseClass.call(this, x, y);
this.img = img;
}
ImageClass.prototype = Object.create(BaseClass.protoype);
ImageClass.prototype.constructor = ImageClass;
function LayerClass(img, w, h, x, y){
ImageClass.call(img, w, h, x, y);
this.collection = [];
this.createSprite = function(img, r, a, w, h, x, y){
this.collection.push(new Sprite(img, r, a, w, h, x, y));
}
}
LayerClass.prototype = Object.create(ImageClass.prototype);
LayerClass.prototype.constructor = LayerClass;
function SpriteClass(img, r, a, w, h, x, y){
ImageClass.call(img, w, h, x, y);
this.r = r;
this.a = a;
}
SpriteClass.prototype = Object.create(ImageClass.prototype);
SpriteClass.prototype.constructor = SpriteClass;
In my code each of the inherited classes uses call() to pass 'this'
The problem being is that if I have a Layer object that contains any Sprite objects, I would like the Sprite objects to have a parent (super) reference and I can't do this because the class constructors use this to set properties.
So does anyone know how I could pass the parent or (and I know this is going to sound dumb, it's late) be able to get the parent scope this in the class constructor?
While writing this I realized that it might be as simple as setting the parent property after the object is set as a child but I'm looking for confirmation if that's the best way or if anyone knows something better. Also feel free to tell me I know nothing about prototype because I'm still learning it. :-)
-Thanks
Would this work? Its not automatic, but still works. Javascript does not have native support for classes, so it has its limitations.
function LayerClass(img, w, h, x, y){
ImageClass.call(img, w, h, x, y);
this.collection = [];
this.createSprite = function(img, r, a, w, h, x, y){
var spriteObj = new Sprite(img, r, a, w, h, x, y);
spriteObj.parent = this;
this.collection.push(spriteObj);
}
}
You will be able to access the parent variable of spriteObject.
Also, if you are looking for inheritance, try coffee script. It compiles back to javascript and handles most of the inheritance problems for you.

Why are the object and constructor.prototype set to Base in JavaScript?

Here is my little program. When I check the value of rec in the debug mode, the object is Base { x=0, y=0, w=10, more...}. Should it be Rectangle? Also the constructor.prototype is Base. Why not Shape?
function Base() {
}
function Shape(x, y) {
this.x = x;
this.y = y;
}
Shape.prototype = new Base();
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.log("x = " + this.x + " y = " + this.y);
};
function Rectangle(x, y, w, h) {
Shape.call(this, x, y);
this.w = w;
this.h = h;
}
Rectangle.prototype = new Shape();
Rectangle.prototype.area = function() {
return this.w * this.h;
};
var rec = new Rectangle(0, 0, 10, 10);
console.log(instanceOf(rec, Rectangle));
function instanceOf(object, constructor) {
while (object != null) {
if (object == constructor.prototype)
return true;
if ( typeof object == 'xml') {
return constructor.prototype == XML.prototype;
}
object = object.__proto__;
}
return false;
}
Have a look at Why [not] to use the new keyword here?. You might not use it and create a new instance of it, but rather just inherit from Base.prototype.
Also the constructor.prototype is Base. Why not Shape?
I'm not sure which constructor you are referring to here:
The constructor property of all your objects is Base, as all of them inherit this prototype from the Base.prototype object. You did not overwrite it after setting up the inheritance chains. It is not really necessary, but good style: Shape.prototype.constructor = Shape and Rectangle.prototype.constructor = Rectangle - where those prototype objects are the overwritten ones which inherit from Base.
The constructor parameter of your instanceOf function. You pass in Rectangle there, so constructor.prototype is the prototype object of Rectangle, which inherits from Base but is different.
When I check the value of rec in the debug mode, the object is Base { x=0, y=0, w=10, more...}
Usually not. Is Base something special, e.g. a host object? Your rec object is an instance of Base, so it might be displayed differently because of that.
rec is just an object which inherits from Rectangle.prototype which inherits from Shape.prototype which inherits from Base.prototype which inherits from​… Assuming Base is the function you defined, from Object.prototype which inherits from null.

Categories

Resources