How to inherit using Object.create() - javascript

I created an instance of Shape using Object.create() method and tried accessing the property of Shape as follows, but the inherited property becomes undefined:
function Shape(){
this.x = 10;
this.y = 20;
}
var rectangle = Object.create(Shape);
console.log(rectangle.x) // undefined

To create an instance of a constructor, use new
var rectangle = new Shape()

May declare the shape as an object instead of function though functions are first class object in js. Create a function inside this object and return the required value from this function
var shape = {
userProperty: function(x, y) {
this.x = x || 10; // if no value of x is passed it will be 10
this.y = y || 10; // if no value of y is passed it will be 10
return {
x: this.x,
y: this.y
}
}
}
var rectangle = Object.create(shape);
console.log(rectangle.userProperty(40).x) // 40

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.

Can't get Javascript object to construct (within object) after inheritance

I've created a Javascript object for a Player class for a game I've been working on which "inherits" from a Collidable class using the follow line:
Player.prototype = new Collidable(50, 50, 70);
This Collidable class has an instance of a Vector class, which is instantiated in my code like:
this.pos = new Vector(x, y) || new Vector(50, 50);
My problem is that I can create a new Collidable object just fine, and the vector inside will have the values for x and y given in the first two arguments of the new Collidable(x, y, diameter) part. However, when a new Player is created (current = new Player();) the vector's values for x and y become NaN.
Below I have included the code for the Collidable constructor and Player constructor.
Collidable:
Collidable = function Collidable(x, y, d){
this.pos = new Vector(x, y) || new Vector(50, 50); // Position of centre
this.diam = d || 50; // Diameter
this.col = new Color().randomRGB(); // For debug
}
// More functions below
Player:
Player = function Player(){
this.health = 100;
this.facing = 0;
this.sprites = new Image();
this.sprites.src = "./npc-oldman1.png";
this.spriteNo = 0;
this.moveSpeed = 2;
}
Player.prototype = new Collidable(50, 50, 70);
// More functions below
I suspect this is related to this question, but haven't been able to work out what is going wrong.
My full code is availabe here. What it should do is display an image of an old man that moves to where the mouse clicks (it does flash at (50, 50) (where the Player is created) right at the beginning, or when you manually change the pos value). I have had the code working before I added the Collisions class.
Thanks in advance.
The problem seems to be a mix between Inheritance issues with nested objects and reason [not] to use the new keyword/shared properties from constructor inheritance. The solution will be
function Player(){
Collidable.call(this, 50, 50, 70); // give *this* instance an *own* Vector
this.health = 100;
this.facing = 0;
this.sprites = new Image();
this.sprites.src = "./npc-oldman1.png";
this.spriteNo = 0;
this.moveSpeed = 2;
}
Player.prototype = Object.create(Collidable.prototype); // without creating instance
Your vector.js code does this check:
if (typeof x === 'NaN' || typeof y === 'NaN')
However, typeof NaN == 'number'. You want isNaN(x), or more cryptically, x != x
Fixing that, it becomes obvious that your problem is elsewhere. This line:
var diff = new Vector(this.getCentre.x - x, this.getCentre.y - y);
Should be one of:
var diff = new Vector(this.getCentre().x - x, this.getCentre().y - y);
var diff = this.getCentre().diff(new Vector(x, y))
There are quite a few sets of missing parentheses.
Perhaps there is a different issue with your code than what you have shown. Perhaps it is out of order? I was unable to reproduce NaN, here is what I used:
html
<div>Vector</div>
<div><span>X: </span><span id="x"></span><div>
<div><span>Y: </span><span id="y"></span></div>
js
var Vector = function(x,y){
this.x = x;
this.y = y;
}
var Collidable = function Collidable(x, y, d){
this.pos = new Vector(x, y) || new Vector(50, 50);
}
var Player = function Player(){
this.health = 100;
}
Player.prototype = new Collidable(50, 50, 70);
var current = new Player();
console.log(current);
console.log(current.pos);
document.getElementById("x").innerHTML = current.pos.x;
document.getElementById("y").innerHTML = current.pos.y;
demo: http://jsfiddle.net/MuRNx/

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