Accessing a class function with array of objects - javascript

I was coding in p5.js, and I noticed a problem that I couldn't pass.
I have a class named "Boxes". I am already using the functions that "Boxes" have. But while I tried to use that functions apply to an array of objects, It didn't work. How can I fix this problem?
class Boxes
{
constructor()
{
this.x;
this.y;
this.r=222;
this.g=55;
this.b=111;
}
show()
{
fill(this.r,this.g,this.b);
rect(this.x,this.y,50,50);
}
}
For standard variable it works perfectly like this.
var box1 = new Boxes();
box1.show(); // It works.
When I tried something different it doesn't work. The example below.
var myboxes = [{'x':this.x, 'y':this.y}]; // That's OK :)
myboxes.push({x:100, y:100}); // That's OK too :)
myboxes[1].show(); // But. It gives an error :/
It says: "myboxes[1].show is not a function"
Although I write the show() function, with parentheses. It says
"myboxes[1].show is not a function" It works fine when I use
box1.show(). How can I access the functions using an array of objects?
Shall I try something else? What are you suggesting?

If you want to have an array of Boxes, you can .push() the new objects like:
class Boxes {
constructor(param) {
this.x = param.x; //Assign the x
this.y = param.y; //Assign the y
this.r = 222;
this.g = 55;
this.b = 111;
}
show() {
console.log(this.x, this.y); //Test code,
//fill(this.r,this.g,this.b);
//rect(this.x,this.y,50,50);
}
}
var myboxes = [];
myboxes.push(new Boxes({x: 3,y: 20})); //Create a new box and push to the array
myboxes.push(new Boxes({x: 30,y: 200})); //Create anothe one and push to the array
myboxes[1].show(); //<-- You can show the x and y of element 1

If you create a non-Boxes object, it doesn't have show anywhere in its prototype chain. But that's OK, if you have access to the class, you can call the prototype method with your non-Boxes object as the this:
class Boxes {
show() {
console.log(this.x);
}
}
var myboxes = [{'x':this.x, 'y':this.y}];
myboxes.push({x:100, y:100});
Boxes.prototype.show.call(myboxes[1]);
But note that you'll also need to put r, g, and b properties on your non-Boxes object in order for show to work.

Related

How to handle several instance on the same Class in a plugin?

I have a JS plugin using es6 class syntax. I'm not sure on the way to handle several instances of the class versus once instance with a several element inside.
This plugin can have an array an unlimited number of image nodes as parameters.
This is the class syntax I have so far
(function(window) {
function handle(element, options) {
let handles = [];
if (element.length) {
for (var i = 0; i < element.length; i++) {
handles.push(new Plugin(element[i], options));
}
} else {
handles.push(new Plugin(element, options));
}
return handles;
}
class Plugin {
constructor(element, options) {
this.element = element;
this.init();
}
init() {
//get its translated value
this.methodA();
//apply its translation even if not visible for the first init
this.methodB();
}
methodA() {
this.element.classList.add('test');
}
}
return handle;
});
I would like to get rid of this handle function. What is the other way to have an instance of plugin for every element? and to be able to have the classPlugin at the top level without the need for this handle function.
I don't see any other way that having several instances of the class, because each instance get specified info for each image (height, offset, etc). Maybe I am missing something obvious here...
You can't actually instantiate an instance of a class without a loop. You may try eval. But it's not recommended. It's a bad practice.
Now let me explain why it is not possible.
JavaScript does not have classes and instances, it has only objects, which can delegate to other objects.
To create two objects based on a single object, but behind the scenes, there aren’t really two ‘instances’ of the Point object, there are just two objects that delegate to the original one. When you use new, JavaScript is actually just creating an object and setting its prototype to the object returned by the constructor function. Imagine if the example had been expanded to include a shared method like this:
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.logCoords = function () {
console.log(this.x, this.y);
};
var a = new Point(1, 2);
console.log(a.x); // logs '1'
a.logCoords(); // logs '1 2'
Behind the scenes, what’s happening is something more like this:
var Point = function (x, y) {
this.x = x;
this.y = y;
};
Point.prototype.logCoords = function () {
console.log(this.x, this.y);
};
var a = {};
a.__proto__ = Point.prototype; // see note below about this
a.constructor = Point;
a.constructor(1, 2);
console.log(a.x); // logs '1'
a.logCoords(); // logs '1 2'

How do I get the object created during a constructor?

Beginner question here. I am trying to use the class syntax in javascript to make an object. I want to add the object as whole to an arraylist when it is created. I would also like to loop through that array later. My question: how do I add the actual object created in the constructor. Example code:
class Example {
constructor(x,y,z) {
this.x = x;
this.y = y;
this.z = z;
}
}
Ideally I want to, when an Example object is created, add it to an array of examples. Can I do this within the constructor function? Also, if I have an array of Examples: what is the correct syntax for for in looping through it.
var examples = []
for Example in examples
the constructor can simply add the object like this
var examples = []
class Example {
constructor(x,y,z) {
this.x = x;
this.y = y;
this.z = z;
examples.push(this)
}
}
Just push it into an array:
class Example {
constructor() {
Example.instances.push(this);
}
}
Example.instances = [];
And you can iterate that like:
for(const instance of Example.instances) {
//...
}
this is a little strange, but you should be able to add this line to the bottom of your constructor:
examples.push(this);

Subclass of a Subclass?

I've been writing a game engine, and I wanted to re-organize my code to make it more modular. Currently, I have a main function called Isometric that accepts the canvas to draw.
var iso = new Isometric('canvas');
So far so good. Next, I had .newMap() to create a new map.
var map = iso.newMap(10,1,10); // Creates 10x1x10 map
However, I want to change that since there might be some confusion with the .map property (since this returns an array called map).
I wanted the syntax to look like this:
iso.Map.create(10,1,10);
So I tried something like this:
function Isometric(id) {
this.Map = function() {
this.create = function() {
}
}
}
But when I went to access it, I realized that the second level of this still refers to the same first level this. So, I can't create a sub-class of the Map object.
I've looked at a few different methods, but none of them had clear examples and I couldn't get them to work.
Among them, I'm aware that you can use prototype, and Object.create() but I've not gotten much success.
How can I do this?
The other solution I have is to do something like this:
function Isometric('id') {
this.Map = {
'create': function() { },
'load': function() {}
}
}
and then access it like
iso.Map['create'];
but I don't like that at all. Any clean methods of doing it?
My main interest is an example with the third-level method ..create() inside .map. If you could provide me with documentation related to my question that I have not yet found, that would be nice. But even mozilla docs didn't seem to help.
I think the appropriate thing to do here is to namespace your Map constructor under the Isometric constructor. Here is how you could go about it.
function Isometric(id) {
this.id = id;
}
Isometric.prototype = {
constructor: Isometric,
test: function() {
return "I'm an instance of Isometric.";
}
};
Here we do the namespacing and add a create() helper method to the Map constructor to create its instances.
Isometric.Map = function Map(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
}
Isometric.Map.prototype = {
constructor: Isometric.Map,
test: function() {
return "I'm an instance of Isometric.Map.";
}
};
// Helper method to create `Map` instances
Isometric.Map.create = function create(x, y, z) {
return new Isometric.Map(x, y, z);
};
Usage:
var iso = new Isometric('id123');
var map = new Isometric.Map(0, 7, 99);
var map2 = Isometric.Map.create(1, 2, 3);
iso.test(); //=> "I'm an instance of Isometric."
map.test(); //=> "I'm an instance of Isometric.Map."
map2.test(); //=> "I'm an instance of Isometric.Map."
Namespaces
It's important to note that the namespacing we just did prevents collisions with the new Map class in ES6 (new JS version) - more about ES6 Maps here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map.
With that said, it's always important to namespace your code under one main object (you could call it app) and only make that namespace available globally.
In your case you could do something like the following example:
;(function(win) {
// Isometric
function Isometric(id) {
this.id = id;
}
Isometric.prototype = {
constructor: Isometric,
test: function() {
return "I'm an instance of Isometric.";
}
};
// Map
function Map(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
}
Map.prototype = {
constructor: Map,
test: function() {
return "I'm an instance of Isometric.Map.";
}
};
// Helper method to create `Map` instances
Map.create = function create(x, y, z) {
return new Map(x, y, z);
};
// Namespace Map under Isometric
Isometric.Map = Map;
// Expose globally
// --------------------
win.app = {
Isometric: Isometric
};
}(this));
Example:
var nativeMap = new Map();
nativeMap.set('name', 'joe'); //=> {"name" => "joe"}
var myMap = new app.Isometric.Map(33, 7, 99);
myMap.test(); //=> "I'm an instance of Isometric.Map."
// Native map wasn't affected (good)
nativeMap.test(); //=> TypeError: undefined is not a function
I will leave the other answer as accepted because it was more detailed and even told me about my code possibly becoming deprecated as is.
That being said, I want to re-iterate Felix King's solution. I will figure a way of combining both ideas (using namespaces and using Felixs) but here's what the partial solution was.
function Isometric(id) {
this.Map = function() {
this.create = function() {
return 5;
};
};
}
That was the set up I had. 5 is just an arbitrary value.
var iso = new Isometric(); // New instance of Isometric()
var mapping = new iso.Map(); // Access to Iso's mapping functions
var map = mapping.create(); // Should return a map array
console.log(map); // Prints 5
For anyone following along on this, if you want to see how I end up implementing it, then see my Github project: https://github.com/joshlalonde/IsometricJS
I'll play around with the code in sometime this weekend.
Again, thanks for your help everyone! Good luck to anyone trying to do something similar.

Javascript TypeError: ... is not a Constructor - How can I make Constructors from Constructors?

I am trying to do object inheritance in Javascript - is the following possible to do in javascript?
Grandparent Object:
var shape=function(paramOpts){
this.opts={x:0,y:0,h:10,w:10};
$.extend(true,this.opts,paramOpts);
this.sides=0;
this.fill='#fff';
this.outline='#000';
// some methods
};
Parent Object
var square=new shape();
square.sides=4;
Child Object
var redbox=new square();
redbox.fill='#f00';
Running this I get the error TypeError: square is not a Constructor.
How can I make square a Constructor?
When you create square you don't get Function returned as your prototype, you get shape.
There are several ways you can inherit like this, personally; I like to use Object.create() i.e
function shape(paramOpts){
this.opts={x:0,y:0,h:10,w:10};
$.extend(true,this.opts,paramOpts);
this.sides=0;
this.fill='#fff';
this.outline='#000';
// some methods
};
var square = Object.create(shape);
square.sides = 4;
var redbox = Object.create(square);
redbox.fill = '#f00';
Support for Object.create goes as far back as IE9 but no farther, there are plenty of shims that will do this for you though.
If you don't want to use a shim you can do it the classical way, your shape definition's methods would be defined on the prototype chain for shape i.e:
shape.prototype.setFill = function shape_fill(colour) {
this.fill = colour;
return this;
};
And your following definitions of square and redsquare would simply "leech" the prototype from shape like below:
function square(){}
square.prototype = shape.prototype;
function redbox() {}
redbox.prototype = square.prototype;
I hope this helps and I've been clear :)
If I've not been clear, there's loads and loads of information on the various Object. functions on MDN
edit
Continuation from my last comment below, you can add a super method to your prototype to fire the construct like below:
redbox.prototype.super = square.prototype.super = function super() {
return shape.call(this);
};
With that you should be able to call square.super() to run the shape construct and you can do the same for redbox to do the same.
You can also include the shape.call(this); code inside your square and redbox function definitions to do it, probably neater but it's your choice in honesty, personal taste lends my favour to prototype.
square is not a function
You cannot instantiate from variable , However , you can instantiate
from function .
Another thing , shape is not a GrandParentObject , It is a constructor in you context(=Class in OOP terminology) .
Use this function :
function inherits(base, extension)
{
for ( var property in base )
{
extension[property] = base[property];
}
}
Shape Class:
var shape=function(paramOpts){
this.opts={x:0,y:0,h:10,w:10};
$.extend(true,this.opts,paramOpts);
this.sides=0;
this.fill='#fff';
this.outline='#000';
// some methods'
return this ;
};
Grandparent Object :
var shape1=new shape();
Parent Object
var square=new shape();
inherits(shape1,square)
square.sides=4;
Child Object
var redbox=new shape();
inherits(square,redbox)
redbox.fill='#f00';
UPDATE:
I note your comment in Shape Class (//some methods) . However , if you talk about OO, Adding Methods to Your shape Class , it will be as following (Using Prototype) :
shape.prototype.Perimeter=function(){
return this.opts.w * this.opts.h ;
}
Then you can apply it in your object shape1
shape1.Perimeter(); // 10*10=100
Here is a simple example of inheritance in JavaScript:
// Parent class
function Shape (sides) {
this.sides = sides;
this.fill='#fff';
}
// Child class
function Square (fill) {
// run the Parent class' constructor
Shape.call(this, 4);
this.fill = fill;
}
// Instantiate Child class
var redbox = new Square('#f00');

Creating a javascript object to emulate a class and static methods?

Can anyone help? I have the following object in javascript... from what i understand each "INSTANCE" of my calendar will have its own variables.
My question is i need to insert a method/function name called "InitilizeHolidays" this needs to add to an array but the details need to be same in all instances ... I was thinking about some kind of STATIC method call if this is possible ..
Of course if i insert this on "prototype" its going to be specific to each instance and i need for it to effect all instances.
Is it possible to initilise variables that effect ALL instances and ONLY specific instances? Where must i insert these?
Any help really appreciated
function Calendar() {
// I presume variables set here are available to "ALL" instances
}
Calendar.prototype = {
constructor: Calendar,
getDateTest: function() {
return "date test";
},
getDateTest2: function() {
return "date test";
}
};
Yes, it is possible. In yui they use
YAHOO.lang.augementObject(Calendar,{/* Properties go here*/});
But to simplify for you if your not using YUI you can do this
Calendar.MyStaticVar = {/* Any variables you want*/}
That will allow you to define a static variable called MyStaticVar, in this example, its an object, but it could be a string, a number, whatever you want. Then to use it, all you do is go
Calendar.MyStaticVar
The Augment object in YUI is quite nice though, because you can say
YAHOO.lang.augementObject(Calendar,{
StaticVar1:'somevalue',
StaticVar2:{/*Object value*/},
StaticVar3:393,
SomeStaticFunction:function() {}
});
As opposed to
Calendar.StaticVar1 = 'somevalue';
Calendar.StaticVar2 = {/*Object value*/};
Calendar.StaticVar3 = 393;
Calendar.SomeStaticFunction = function() {};
There's something confusing about Javascript's prototype inheritance. Let me explain.
Fields defined at the prototype object are shared by all instances. The problem is that you can't really notice that because assignment into a field of an object o is always carried out at the o instance and not at the prototype.
Thus, you have two options for defining static fields.
(1) Define a field at the prototype object. When you want to change it you must change it through the prototype object and.
function Calendar() {
}
Calendar.prototype = {
constructor: Calendar,
y: 'y',
};
function go()
{
var c1 = new Calendar();
var c2 = new Calendar();
alert("c1.y=" + c1.y + " c2.y=" + c2.y);
// now setting y to 'YYYYY';
Calendar.prototype.y = 'YYYYY';
// both c1 and c2 'see' the new y value
alert("c1.y=" + c1.y + " c2.y=" + c2.y);
}
The danger with this is you may accidentally try to set the y field via one of the instances, as in: c1.y = 5555, in which case the assignment will take place on the c1 object but not on the c2 object.
Hence, you can use the second option which is safer, but requires some more keystrokes...
(2) Use Javascript's encapsulation trick to make sure the prototype field is only accisble via getter and setter methods.
function Calendar() {
}
function initCalendarPrototype()
{
var y = 'y';
Calendar.prototype = {
constructor: Calendar,
getY: function() { return y; },
setY: function(arg) { y = arg; },
};
}
function go()
{
initCalendarPrototype();
alert("c1.getY()=" + c1.getY() + " c2.getY()=" + c2.getY());
// now setting y to 'YYYYY' via setY()
// Can be invoked on either c1, c2 or Calendar.prototype
c1.setY('YYYYY')
// both c1 and c2 'see' the new y value
alert("c1.getY()=" + c1.getY() + " c2.getY()=" + c2.getY());
}
well,I think static property is not for you.
consider this:
function MyClass(specialProp) {
if (specialProp) {
this.prop = specialProp;
}
}
MyClass.prototype = {"prop":"defaultValue"};
var foo = new MyClass("changed"), bar = new MyClass();
alert(bar.prop); //got the property from the prototype chain
alert(foo.prop); //special property of the instance

Categories

Resources