Function Scope in P5.js - javascript

I am using the p5.js library as the basis for my program due to its ease of implementing visual features to javascript, however I have run into a bit of trouble.
I am wanting to create multiple canvases within the same file to be displayed on an html page. I have attempted a few means of doing this and have had the most success with this means of achieving it. Effectively separating two p5 sketches via “instance mode” to then be able to reference them from separate div elements in the html file.
This means works for what I want it to. I can create x number of instances and separate them into x number of div elements on my html page without problem.
However, an integral feature of my program is that when a key is pressed it calls a function that is specific to a particular canvas. Using the keyPressed() function in p5 I am able to achieve this. However, it is not scalable to multiple canvases.
Effectively it seems that (at least with my implementation) that putting this function inside of multiple instances causes the function to only be called in the first instance and ignoring the others. To go around this I was thinking I could implement this keyPressed() function outside the scope of the instances and then have that keyPressed() function call a function from each instance to achieve what I desire.
This is where my problem has arisen, I do not know how I can refer to a function within an instance from outside the local scope of that instance. Here is some example code of what I am wanting to achieve. I am not very experienced with JavaScript and any help would be much appreciated.
function keyPressed() {
if(keyCode === [SOME_KEY]) {
//Call doSomething() from sketch1 and sketch2
}
}
//Sketch 1
var sketch1 = function( p ) { // p could be any variable name
p.setup = function() {
createCanvas(); //etc
};
p.doSomething = function() {
//etc
}
};
var myp5 = new p5(sketch1, 'c1');
// Sketch Two
var sketch2 = function( p ) {
p.setup = function() {
createCanvas(); //etc
};
p.doSomething = function() {
//etc
}
};
var myp5 = new p5(sketch2, 'c2');

Related

An strucure to share data between scopes

I am just learning JS and try to write a simple game. So I made a basic structure witch should look something like this (pseudo c++ code):
if (!game.game-stage)
game.ResetGame(); // initialize game objects
if (player1.score > MAX_SCORE || player2.score > MAX_SCORE)
game.end-round(); stop(1000);
else
game.Update();
game.Render();
Then I try to write it in JS:
function main() {
if (gamest != true) {
resetgame();
gamest = true;
}
/* UPDATE SECTION */
if (score1 > 9 || score2 > 9) {
endround();
setTimeOut(update, 1000);
}
else {
update();
}
/* RENDER SECTION */
draw();
}
Other functions in main() does now have access to objects initialized in resetgame() function. The other problem that appears is that setTimeOut(update, 1000) does not work, when I did put all object to global scope for testing.
resetgame() procedure looks pretty much like this:
function resetgame() {
var paddle1 = new GameObject(20, 80, "LEFT");
[...]
Does that structure makes any sens?
The problem
function main() {
if (gamest != true) {
resetgame();
gamest = true;
}
The resetgame() function is bound inside an if scope. It cause the objects initialized inside this scope to be destroyed after program leaves that scope.
Closure solution
To get use of closure concept we need:
variable
body of logic that variable is bound to
environment that is saved during the closure's instantiation, this is for free variables that exist within the body to be bound when the closure variable is evaluated.
So in this example, we would need a bunch of free object inside the function main() body to save data evaluated by resetgame(). One option will be to pass all those object by arguments to the resetgame() and rewrite it to initialize all arguments to its inner objects.
Simple OOP solution
In a game we usually have a lot of objects, so the closure concept will get to complex and memory consuming. The better solution will be to encapsulate all main functions in to one object so we can easy exchange data and pass the object where-ever we need. That let us create an easy to menage structure, e.g.:
var App = {
Load: function() {
this.frame = new Frame();
},
// UPDATE
Update: function() {
this.frame.updatePosition();
},
// RENDER
Render: function() {
this.frame.draw();
}
};
function Main() {
var app = App;
app.Load();
setInterval(MainLoop(app), 1000/60);
}
function MainLoop(app) {
// main application render
app.Render();
// main application update
app.Update();
}
Someone just remind me about thus question. I'm not a JS expert yet but for that application I find my solution. I know that could be solved better but this solution is good enough for the little game I been writing. But if someone have a better one, I will be glad to hear your opinion.

scope Issue seeing object methods

I have tried searching through a lot of S.O. pages but nothing has touched EXACTLY on this top while also NOT USING JQUERY.... I am trying to stick to pure JavaScript as I want to learn it 115% before advancing my current knowledge of JQuery.
I have an object called ScreenResizeTool like this...
function ScreenResizeTool(currImg) {
window.addEventHandler('resize', function() {
listen(currImg);
}, true);
}
and a method like this...
ScreenResizeTool.prototype.listen = function(currImg) {
//Random Code For Resizing
};
My trouble is probably obvious to an experienced JavaScript user but I am having trouble not making this into a messy dirty awful OOP set. I have done various tests to show and prove to myself that the this inside the addEventHandler changes when it becomes bound to the window. This much I assumed before testing but I was able to see that once window.resize event happens the listen method is gone and not a part of the global window variable....
I have also tried adding a this capture such as this.me = this inside the object constructor however it also couldn't see the me variable once it ran. Once the window took the function over it no longer knew anything about the me variable or any reference to my class methods....
I am aware that I could separate this differently but my goal here is to learn how to fully encapsulate and use as many clean OOP structures as possible as I just came from the .NET world and I need it in my life.
I am also aware that I could make messy calls and or store this object or access to the methods inside the window variable but that seems outright wrong to me. I should be able to fully encapsulate this object and have its events and methods all implemented in this class structure.
I also know that the currImg variable is not going to be seen either but lets start small here. I assume once I figure out my incorrect train of thought on scope for JavaScript I should be fine to figure out the currImg problem.
I know there's 1000 JavaScript programmers out there waiting to rip me a new one over asking this simple question but I gotta know...
Thoughts anyone?
this inside a function bound to a DOM Object (like window) will always refer to that object.
this inside a constructor function will always refer to the prototype.
A common practice to circumvent the this issue, as you mentioned, is to cache it in a variable, often called self. Now you want the variables and properties of your object available after instantiation, so what you need is the return keyword, more specifically to return the parent object itself. Let's put that together:
function ScreenResizeTool() {
var self = this;
// method to instantiate the code is often stored in init property
this.init = function() {
window.addEventListener('resize', function() {
self.listen(); // self will refer to the prototype, not the window!
}, true);
};
return this;
}
ScreenResizeTool.prototype.listen = function() { // Dummy function
var h = window.innerHeight, w = window.innerWidth;
console.log('Resized to ' + w + ' x ' + h + '!');
};
Pretty easy huh? So we have our prototype now, but prototypes can't do anything if there's not an instance. So we create an instance of ScreenResizeTool and instantiate it with its init method:
var tool = new ScreenResizeTool();
tool.init();
// every time you resize the window now, a result will be logged!
You could also simply store the listen & init methods as private functions inside your constructor, and return them in an anonymous object:
function ScreenResizeTool() {
var listen = function() { ... };
var init = function() { ... };
// in this.init you can now simply call listen() instead of this.listen()
return {
listen: listen,
init: init
}
}
Check out the fiddle and make sure to open your console. Note that in this case I'd rather use the first function than the second (it does exactly the same) because prototypes are only useful if you have multiple instances or subclasses
The whole concept of this in JavaScript is a nightmare for beginners and in my code I usually try to avoid it as it gets confusing fast and makes code unreadable (IMHO). Also, many people new to JavaScript but experienced in object-oriented programming languages try to get into the whole this and prototype stuff directly though the don't actually need to (google JS patterns like IIFE for example as alternatives).
So looking at your original code:
function ScreenResizeTool(currImg) {
window.addEventHandler('resize', function() {
listen(currImg); // global function listen?
}, true);
}
ScreenResizeTool.prototype.listen = function(currImg) {
//Random Code For Resizing
};
First off, you probably mean addEventListener instead. In its callback you refer to listen but as a global variable which would look for it as window.listen - which doesn't exit. So you could think to do this:
function ScreenResizeTool(currImg) {
window.addEventHandler('resize', function() {
this.listen(currImg); // what's this?
}, true);
}
As you want to use the prototype.listen function of ScreenResizeTool. But this won't work either as the event listener's callback function is called with a different this and not the this that is your function scope.
This is where something comes in which makes most programmers cringe, you have to cache this, examples from code I've seen:
var _this = this;
var that = this;
var _self = this;
Let's just use the latter to be able to refer to the function within the event callback:
function ScreenResizeTool(currImg) {
var _self = this;
window.addEventListener('resize', function() {
_self.listen();
}, true);
}
Now this will actually work and do what you want to achieve: invoke the prototype.listen function of ScreenResizeTool.
See this JSFiddle for a working example: http://jsfiddle.net/KNw6R/ (check the console for output)
As a last word, this problem did not have anything to do with using jQuery or not. It's a general problem of JS. And especially when having to deal with different browser implementations you should be using jQuery (or another such library) to make your own code clean and neat and not fiddle around with multiple if statements to find out what feature is supported in what way.

How to conceal the functions

Hi,
I have my main file in which I include my javascript file.
In my javascript file I have this
$(document).ready(function(){
//some functions here
});
I want all the functions just available to this page and I know you can kinda conceal them to outside world of javascript by doing something like
(function(){
$document.ready(function(){
//my functions
)};
}).init();
but I am not 100% sure how would it be called or whether its even the right way.
Anyone shedding light on this would be a great help!
In javascript everything declared inside a function is only available inside that function (except for when you declare a variable without the keyword var).
So everything inside the function that you pass to $().ready() is only available inside that function.
$(document).ready(function () {
//all code here is scoped inside this function, so it can't be accessed
// outside of this function
});
Like the first comment says you can't hide them from the user, if they really want to see it, they will see it.
You can clean them up in a way if you really wanted to, something like
var mySpace = {};
mySpace.init = function() {
// your init functions here
};
in doc ready you just call
mySpace.init();
I am not sure if this is what you wanted but it is the way I understood the question
(function(){
var secret1 = function(msg) {console.log("Secret Message:" + msg);}
$document.ready(function(){
secret1("this can only be called from within");
)};
})();
secret1("this will cause a script error");
It sounds like the thing you are looking for is a 'javascript obfuscator'. Here is an example one. It makes the code much harder to read and copy. But as others have said, you can't actually fully hide javascript.
The problem here is that JavaScript is intrinsically a client-side scripting language unless using a server-side javascript application such as node.js.
As long as JavaScript is being used in this way, the entirety of your code will be downloaded much like downloading a .txt file from a website. The only real difference is that the ".js" extension and its inclusion in html <script> tags or in an AJAX call will force the user's browser to render it as JavaScript.
If you want to make the script a little harder for the user to find, however, this is doable. I recommend having your website retrieve the script via AJAX and appending it to the DOM. You can do this with require.js or by using Kickstrap and making your script into an "app." The script won't appear as a link in the DOM and the user would really have to search for it. You can make it even more difficult (without compromising the integrity of your site) by minifying the script. This will make it run faster while inadvertently making it less human-readable on the front end.
In JavaScript there is only function scope (the exception argument in try-catch being an exception). ES5 will let you use let (no pun intended) to achieve block scope but it wont be usefull untill majority of UAs implement it.
So your functions are concealed from the outside world, if with outside you mean outside the dom ready event.
$( document ).ready( function () {
var myFunc = function () {};
} );
myFunc();// <- ReferenceError: myFunc is not defined
You can't really hide the functions, as it's in the source code of a file downloaded by the client, but you can make it so they can't access your functions from javascript.
(function() {
var doStuff = function() {
// Not Accessible
console.log('You can\'t reach me!');
}
return {
'init': function() {
// Accessible
doStuff();
}
}
})().init();
If you are talking about Access Modifiers like public, private etc. Then check out this article on how Javascript handles this. Here are the key components:
//constructor function (class)
function Maths(x, y) {
//public properties
this.x =x;
this.y = y;
//public methods
this.add = function () { _sum = x + y; return _sum; }
this.mod = function () { _mod = x % y; return _mod; }
//public method calls private method
this.show = function () {
this.add();
this.mod();
showResult();
}
//private variables
var _sum=0;
var _mod=0;
//private methods
function showResult() {
alert( "sum: " + _sum + ", mod: " + _mod );
}
}
//end function
//create instance
var plus = new Maths(3, 4);
plus.show();
//static method multiply, you can use it without instance of Maths
Maths.multiply = function (x,y) { return x * y; }
//call static method by constructor function (class) without instance of Maths
var result = Maths.multiply(5,7);
alert(result);
//output: 35

encapsulating javascript inside a namespace

I'm looking to encapsulate my javascript inside a namespace like this:
MySpace = {
SomeGlobal : 1,
A: function () { ... },
B: function () { ....; MySpace.A(); .... },
C: function () { MySpace.SomeGlobal = 2;.... }
}
Now imagine that instead of a few lines of code, I have about 12K lines of javascript with hundreds of functions and about 60 globals. I already know how to convert my code into a namespace but I'm wondering if there's a quicker way of doing it than going down 12K lines of code and adding MySpace. all over the place.
Please let me know if there's a faster way of doing this.
Thanks for your suggestions.
I like to wrap up the namespace like so. The flexibility is huge, and we can even separate different modules of the MySpace namespace in separate wrappers if we wanted too. You will still have to add some sort of _self. reference infront of everything, but at least this way you can change the entire name of the namespace very quickly if need be.
You can see how with this method you can even call _self.anotherFunc() from the 1st module, and you'll get to the second one.
(function (MySpace, $, undefined) {
var _self = MySpace; // create a self-reference
_self.test = function () {
alert('we got here!');
_self.anotherFunc(); // testing to see if we can get the 2nd module
};
_self = MySpace; // reassign everything just incase
}(window.MySpace = window.MySpace || {}, jQuery));
$(function () {
MySpace.test(); // call module 1
MySpace.callOtherModule(); // call module 2
});
// Here we will create a seperate Module to the MySpace namespace
(function (MySpace, $, undefined) {
var _self = MySpace; // create a self-reference
_self.callOtherModule = function () {
alert('we called the 2nd module!');
};
_self.anotherFunc = function () {
alert('We got to anotherFunc from the first module, even by using _self.anotherFunc()!');
};
_self = MySpace; // reassign everything just incase
}(window.MySpace = window.MySpace || {}, jQuery));​
jsFiddle DEMO
Wrap a function body around your existing code to use as scope, hiding everything from global - this will allow you to do internal calls without pasting Namespace. prefix everywhere, neatly hide things you don't want everyone else to see, and will require minimal changes as well.
After that, decide what functions you want to "export" for everyone and assign them to properties of object you want to use as "namespace".

Trying to find a proper way to have global access to a canvas

I'm still kinda new to Javascript and noticed in lot of places in my code I am using JQuery to get a reference to my canvas element like this:
$('#myCanvas')[0].getContext('2d');
I have my suspicions that it is slowing my site down because I have it in a lot of places that may be called quite often. Ideally, I'd just do this once and access the context from any javascript page.
I tried to make a global variable but it didn't see to work (probably because it runs before the page can load) so instead I put this function in global scope in my first referenced javascript file:
var drawingCanvasContext;
function getDrawingCanvas() {
if (drawingCanvasContext == null) {
drawingCanvasContext = $('#myCanvas')[0].getContext('2d');
}
return drawingCanvasContext;
}
So then whenever I need the canvas in my code I just call that method.. But it just seems rather.. messy. I doubt this is an uncommon desire so I'm curious of the proper solution. I'd prefer it just to be a variable instead of a function and to be accessed globally without all these null checks. Does anyone know how to accomplish this? Thanks.
You can simply do this
var drawingCanvasContext = $('#myCanvas')[0].getContext('2d');
instead of defining a function for that.
If you're careful about global scope pollution, you should wrap it up in a function or use namespacing. E.g.
var myNamespace = myNamespace || {};
myNamespace.drawingCanvasContext = $('#myCanvas')[0].getContext('2d');
I've got only two little improvements on your code:
(function(){
// move the var out of the global context by wrapping everything in a closure
var /* static */ drawingCanvasContext;
function getDrawingCanvas() {
if (!drawingCanvasContext) // no need to check for null, defaultvalue is undefined
drawingCanvasContext = $('#myCanvas')[0].getContext('2d');
return drawingCanvasContext;
}
window.getDrawingCanvas = getDrawingCanvas;
})();
Of course you could/should put that method in a namespace object, I guess you have more than one of such.
Ultimately all you can do is store the context around to be retrieved afterwards. The problem I can see here is probably an order of operations, the context is being requested before the page is ready, and possibly you're losing scope with your VAR declaration (i think).
;(function($, window, document) {
/* private */ var canvas = null;
/* private */ var context = null;
$(document).ready(function() {
canvas = $("#myCanvas")[0];
context = canvas.getContext('2d');
$('body').trigger('CanvasReady', [canvas, context]); // You can fire an event to bind to with jquery for when the canvas is ready.
});
/* public */ window.getCanvas = function() { return canvas; };
/* public */ window.getCanvasContext = function() { return context; };
// You can also use a namespace here too if you want
// window.Canvas = {};
// window.Canvas.GetContext = ... etc ...
})(jQuery, window, document);
This will aquire the canvas when it's ready, fire an event you can subscribe to for when the canvas has been found and is ready for manipulation.
It will expose 2 functions globally:
getCanvas which will get you the Canvas Instance
getCanvasContext which will get you the Canvas Context
You can adapt this to use a registry pattern if you want so it can aquire & store multiple canvas elements/contexts but this is just a simple pattern to show you.
Note: It returns null if the methods are called before the canvas/document is ready, you should be doing all of your setup code after domReady anyway.
You can define a getter on your global variable that will execute each time you read from that variable (see here for tips on making this backward compatible):
var _drawingCanvasContext;//behind the scenes variable that keeps the value
Object.defineProperty(this, "drawingCanvasContext", {
get: function() {
return _drawingCanvasContext || (_drawingCanvasContext = $('#myCanvas')[0].getContext('2d'));
}
});
Here's a fiddle where I set it to 'foo' to show you how it works.

Categories

Resources