How to add context methods to an object - javascript

I'm making a library for math graphing in canvas, and before, my approach was to directly add methods to the global context prototype, as such
CanvasRenderingContext2D.prototype.point=function(x,y){
this.fillRect(x,y,1,1);
};
However, I found out that that was not recommended, so what I'm trying now is to make a global object, as such
window.Graph=function(context){
this.ctx=context;
alert(this.ctx);
this.CanvasRenderingContext2D.prototype.point=function(x,y){
this.ctx.fillRect(x,y,1,1);
};
};
I have also tried
this.ctx.prototype.point=function(x,y){
this.ctx.fillRect(x,y,1,1);
};
All of them return errors like cannot set property 'point' to undefined
The ideal way to call it would be
var g=new Graph(ctx);
g.point(5,5);
What would be the best way to do this?
Thanks

Here's what you are looking for:
function Graph(context) {
this.context = context;
}
Graph.prototype.point = function (x, y) {
this.context.fillRect(x, y ,1, 1);
}
var g = new Graph(context);
g.point(5, 5);

plalx shows a great design pattern...
Here's just another with a constructor:
var Graph = (function () {
// constructor
function Graph(context) {
// "class" properties go here
this.context = context;
}
// "class" methods added to prototype here
Graph.prototype.point = function (x,y) {
this.context.fillRect(x,y,1,1);
};
// return a self reference
return Graph;
})(); // make class available by self-executing
// instantiate your Graph class into a graph object
var graph = new Graph(context);

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'

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');

Extending a javascript object

I'm currently working on a platform game engine using javascript and the HTML5 canvas.
I have an object, "platform" which looks something like this...
var platform = function(pid,px,py,pw,ph) {
//Some variables here... and then we have some functions
this.step = function() {
//Update / step events here
}
this.draw = function() {
//Drawing events here
}
//etc.
}
The step() function has all of the calculations for collision detection while the draw() function draws the platform.
What I want to do is make another object called movingPlatform. This will be almost identical to the current platform except for the fact this one moves.
Rather than copying all of the collision detection code I'd like to be able to extend movingPlatform from platform... and then be able to add some additional code into the step() function to the moving platform can... well... move.
Some additional information...
When the game loads, it generates the level using data from a CSV file. I have an array, platforms[] that stores all of the platforms within it.
So to create a platform it looks like this...
platforms.push(new platform(i,data[1],data[2],data[3],data[4]));
I then make the platforms perform their step and draw events during the game's main step and draw events.
i.e.
for(var i=0; i<platforms.length; i++) {
platforms[i].step();
}
Any help would be awesome. Thanks!
I would use the platform class as a "base" object for the moving platform object.
I would do this via the prototype which is JavaScript's implementation of object oriented programming.
More info here How does JavaScript .prototype work?
+ many more articles on the web
You can use Javascript prototype inheritance functionality:
var baseItem = {
push: function(){alert('push');},
pull: function(){alert('pull')}
}
var childItem = {}
childItem.prototype = baseItem;
childItem.push = function(){
//call base function
childItem.prototype.push.call(this);
//do your custom stuff.
alert('I did it again.');
}
childItem.push();
Fiddle
Rather than pure inheritance, here, I'd go with prototype-extension, unless you build some big, ugly factory, just for the sake of saying that "MovingPlatform" inherited from "Platform" in a pure sense, it's not really what you'd expect it to be.
There are a few concerns (cheating, for one), but if your objects are all based wholly around this, and you're okay with people potentially hacking away in the console, then you don't really have much to worry about.
First, understand what you're doing inside of Platform:
var MyObject = function (a) {
this.property = a;
this.method = function (b) { this.property += b; };
};
Every time you make a new MyObject, you're creating a brand new version of the .method function.
That is to say, if you make 10,000 of these, there will be 10,000 copies of that function, as well.
Sometimes that's a very good and safe thing.
It can also be a very slow thing.
The problem is, because everything in your object is using this, and because nothing inside of the function changes, there's no benefit to creating new copies -- just extra memory used.
...so:
MyObject = function (a) {
this.property = a;
};
MyObject.prototype.method = function (b) { this.property += b; };
var o = new MyObject(1);
o.method(2);
o.property; //3
When you call new X, where X has properties/methods on its prototype, those properties/methods get copied onto the object, during its construction.
It would be the same as going:
var method = function (b) { this.property += b; },
o = new MyObject(1);
o.method = method;
o.method(2);
o.property; // 3
Except without the extra work of doing it yourself, by hand.
The benefit here is that each object uses the same function.
They basically hand the function access to their whole this, and the function can do whatever it wants with it.
There's a catch:
var OtherObj = function (a, b) {
var private_property = b,
private_method = function () { return private_property; };
this.public_property = a;
this.unshared_method = function () { var private_value = private_method(); return private_value; };
};
OtherObj.prototype.public_method = function () {
return private_property;
};
var obj = new OtherObj(1, "hidden");
obj.public_property; // 1
obj.unshared_method(); // "hidden"
obj.public_method(); // err -- private_property doesn't exist
So assuming you don't have much you care about staying private, the easiest way of doing this would be to make reusable function, which rely on this, which you then give to multiple prototypes, through extension.
// collision-handling
var testCollision = function (target) { this./*...*/ },
handleCollision = function (obj) { this./* ... */ };
// movement-handling
var movePlatform = function (x, y, elapsed) { this.x += this.speed.x*elapsed; /*...*/ };
// not really the cleanest timestep implementation, but it'll do for examples
var Platform = function (texture, x, y, w, h) {
this.x = x;
// ...
},
MovingPlatform = function (texture, x, y, w, h, speedX, speedY, etc) {
this.etc = etc;//...
};
Platform.prototype.testCollision = testCollision;
Platform.prototype.handleCollision = handleCollision;
MovingPlatform.prototype. // both of the above, plus the movePlatform method
This is a lot by hand.
That's why functions in different libraries will clone or extend objects.
var bunchOfComponents = {
a : function () { },
b : 32,
c : { }
},
myObj = {};
copy(myObj, bunchOfComponents);
myObj.a();
myObj.b; //32
Your function-reuse goes up, while the horror of writing proper Class-based, hierarchical inheritance, with virtual-overrides, abstracts, and shared-private properties, by hand, goes down.
Getting inheritance right in Javascript is somewhat tricky if you're used to class-based languages.
If you're not sharing a lot of behaviours, you might find it easier to just create some shared methods, then make them available to objects of each platform type.
//Create constructors for each type
var Platform = function(pid,px,py,pw,ph) { //By convention, constructors should start with an uppercase character
...
}
var MovingPlatform = function() {
...
}
//Create some reuseable methods
var step = function() {
...
}
var draw = function() {
...
}
var move = function() {
...
}
//Attach your methods to the prototypes for each constructor
Platform.prototype.step = step;
Platform.prototype.draw = draw;
MovingPlatform.prototype.step = step;
MovingPlatform.prototype.draw = draw;
MovingPlatform.prototype.move = move;
...etc
That said, if you do want to build up a proper inheritance chain, there are plenty of articles available to help you: 1 2 3 4

Functions defined on a object within a prototype

I'm trying to define functions on a object within a prototype like in this example:
function Particle = {
this.calculate.x = 0;
}
Particle.prototype.calculate.calculateX = function() {
//do calculation
}
var particle - new Particle();
If I explore particle in the browser console the 'calculate' object is visible but without any of the functions defined on it.
What am I missing?
Is it even possible to define an object prototype in this way?
Cheers!
Try this way:
function Particle() {
this.calculate.x = 0;
}
Particle.prototype.calculate = {
calculateX: function() {
//do calculation
}
}
var particle = new Particle();
You're not defining calculate on the prototype at all by accessing this.calculate within the constructor. Infact your syntax is entirely wrong there..
function Particle = {
};
should be
function Particle() {
}
Accessing this within the constructor function just writes stuff into that instance object, not on its .prototype.

Categories

Resources