Hey I was wondering how I could add on to my function draw(); draw is used in my canvas engine to update everything within it. What I want to do is create a standalone engine that could say be left un-edited and yet update completely new things just linked to it. For example-
function draw(){
gameloop();
cameraWrapper();
context2D.clearRect(0,0,canvas.width, canvas.height);
}
Now say I create a new app and use this engine.. I want to be able to just create a standalone file linked to the engine say a player object.
player = new object();
function playerupdate(){
stuff;
stuff;
}
Now how could I say add the playerupdate() function into the engine.js's draw() function without editing the engine.js file? would this be like a prototype? if so and even if its not and example would be greatly appreciated! If you have any questions please ask, thanks in advance!
I think inheritance is a bit too complex for this... you can achieve all of what you want with just hooks.
Try something like this:
var postDrawHooks = [];
var draw = function(){
// do stuff
postDrawHooks.forEach(function(hook){hook()});
}
var playerUpdate = function(){...};
postDrawHooks.push(playerUpdate);
Basicaly it is a prototype. If you do not wish to complicate yourself with prototypeing you can use a "home made" inheritance:
Function.prototype.method = function(name, func) {
this.prototype[name] = func;
return this;
};
Function.method('inherits', function(parent) {
var d = {}, p = (this.prototype = new parent());
this.method('uber', function uber(name) {
if(!( name in d)) {
d[name] = 0;
}
var f, r, t = d[name], v = parent.prototype;
if(t) {
while(t) {
v = v.constructor.prototype;
t -= 1;
}
f = v[name];
} else {
f = p[name];
if(f == this[name]) {
f = v[name];
}
}
d[name] += 1;
r = f.apply(this, Array.prototype.slice.apply(arguments, [1]));
d[name] -= 1;
return r;
});
return this;
});
Now for a "class" (there is no such thing in js but this is the correct term ) you can make it inherit another "class" by using myCls.inherits(parentCls)
is there a reason you couldn't trigger events for these framework actions? that way anything listening for a 'draw' event could just hook their logic in that way? if not actual eventing, something like the hooks suggested by #sudhir jonathan would work, though i would suggest creating a method to register generic hooks, this way you could call something like
game.register('draw',myFunctionReference);
and in game object
register : function (hook,func) {
registeredHooks.push({'name' : hook, 'callback': func});
}
and in draw:
function draw(){
gameloop();
cameraWrapper();
context2D.clearRect(0,0,canvas.width, canvas.height);
for (i=0; i < registeredHooks.length; i++) {
var hook = registeredHooks[i];
if (hook.name == 'draw') hook.callback();
}
}
Related
After reading this article regarding pure functions it seems to me that when working when object oriented JavaScript the concept of pure functions doesn't seem to be as simple to implement unless you want to end up calling functions with plenty of arguments or with an array of them.
Lets say I have the following function within a Javascript object.
function demo() {
var self = this;
//fixed in some other method
self.order.owner = null;
self.selectedEvent() = null;
self.order.booking_id = null;
self.order.order_id = null;
self.details = null;
self.notification = null;
self.notifyDesk = null;
self.additionalText = null;
//WILL THIS FUNCTION BE PURE?
self.test = function() {
if (self.order.owner && self.selectedEvent()) {
return true;
}
else if(self.order.booking_id == '4000' || !self.isValid(self.order.order_id) ){
return false;
}
return self.whatever;
};
return self;
}
var myDemo = new Demo();
//whatever other actions over the demo object here
console.log( myDemo.test() );
The method addOrder It is making use of 5 variables outside the function scope and belonging to the object scope.
That's not what I understood to be a "pure" function, but unless we want to call addOrder with 5 parameters, or a single array parameter with 5 elements, it doesn't seem to me we can get a pure Javascript function out of it.
This happens quite often in OO Javascript and accessing the object properties is something pretty common ?
What am I missing? Please delight me!
A pure function is one which for any input x will always produce the same output y and does not change any state. As long as the function does not break those principles, it's a pure function.
Here's an example showcasing the difference between a pure function and some impure functions:
var rect = {
width: 2,
height: 4
};
function areaPure(rectangle) {
return rectangle.width * rectangle.height;
}
function areaImpureMutate(rectangle) {
rectangle.area = rectangle.width * rectangle.height;
}
function areaImpureOuterState() {
// Uses variable declared outside of scope
return rect.width * rect.height;
}
console.log('pure:', areaPure(rect)); // no side effects
// Mutates state
areaImpureMutate(rect);
console.log('mutated:', rect.area);
// Relies on mutable state
rect.height = 5;
console.log('mutable state:', areaImpureOuterState(rect));
rect.width = 5;
console.log('mutable state:', areaImpureOuterState(rect));
The hard-and-fast rule for pure functions is that if I give you the same input regardless of the state of the rest of the program, it will always give me the same output and not mutate the state of the program directly.
So you could rewrite your test function like this to make it almost pure:
function test(obj) {
if (obj.order.owner && obj.selectedEvent()) {
return true;
}
else if(obj.order.booking_id == '4000' || !obj.isValid(obj.order.order_id) ){
return false;
}
return obj.whatever;
};
There's one problem with it: obj.selectedEvent() is an impure function which taints this pure function.
I just started to get into JS lately and I am using module pattern a lot and I really don't know if I am doing it right when it comes to doing inheritance from the module I wrote.
Here are the following .js files I am working on:
define(["src/Inhabitant"], function(Inhabitant)
{
console.log("Coin.js loaded");
return (function()
{
function Coin(stage , position)
{
Inhabitant.call(this, stage, position, "coinGold.png");
}
Coin.prototype =
{
prototype : Object.create(Inhabitant.prototype)
, constructor : Coin
, update : update
}
function update(elapsed)
{
}
return Coin;
})();
});
I have a JS class named as Coin and its parent is Inhabitant:
define([], function()
{
console.log("Inhabitant loaded.");
return (function()
{
var mStage = null;
var mSprite = null;
var mID = -1;
function Inhabitant(stage, position , resource)
{
mStage = stage;
mSprite = new PIXI.Sprite.fromFrame(resource);
mSprite.position = position;
}
Inhabitant.prototype =
{
constructor : Inhabitant
, get position(){ return mSprite.position; } , set position(position){ mSprite.position = position; }
, get x(){ return mSprite.x; } , set x(x){ mSprite.x = x; }
, get y(){ return mSprite.y; } , set y(y){ mSprite.y = y; }
, get id(){ return mID; } , set id(id){ return mID; }
, get sprite(){ return mSprite; }
, update : update
}
function update(elapsed)
{
console.log("Calling update from Inhabitant");
}
return Inhabitant;
})();
});
I am stuck on this one because I can't even call the methods I am supposed to inherit. Even the update function isn't provided by the parent. If I remove the update from Coin it will not call the parent version (I don't know if I have the correct assumption on this one).
Also most of the time I write my classes this way
define([] , function()
{
return function()
{
var o = {};
return o
}
});
This works most of the time since I am creating objects without the need of inheritance that much. But now I need to it in prototypal way so I can reduce code duplication.
What is the proper way of doing Module Pattern with prototypal inheritance given on what I currently have?
This have been asked many times via this link and this link but its not helping my situation.
Any ideas?
I'm working on some script for a set of functions that all operate from one call and take a large number of parameters to return one value. The main function requires the use of 11 other functions which need to work with the same parameters. I have it structured somewhat like this:
function mainfunction(param1, param2, ..., param16)
{
//do a bunch of stuff with the parameters
return output;
}
function secondaryfunction1()
{
//gets called by mainfunction
//does a bunch of stuff with the parameters from mainfunction
}
Is there anything I can do to make the parameters passed to mainfunction available to all the secondary functions without passing them or making them global variables? If not, that's fine, I'll pass them as parameters - I'm curious as to whether or not I can do it more elegantly.
You can place the definition of secondaryfunction1 inside mainfunction:
function mainfunction(param1, param2, ..., param16){
function secondaryfunction1() {
// use param1, param2, ..., param16
}
secondaryfunction1();
}
Update:
As #dystroy pointed out, this is viable if you don't need to call secondaryfunction1 somewhere else. Where the list of parameters would be coming from in this case - I don't know.
You could use arguments to pass to secondaryFunction1 all the arguments of mainfunction. But that would be silly.
What you should probably do, and what is usually done, is embed all the parameters in an "options" object :
function mainfunction(options){
secondaryfunction1(options);
}
function secondaryfunction1(options) {
// use options.param1, etc.
}
// let's call it
mainfunction({param1: 0, param2: "yes?"});
This leds to other advantages, like
naming the parameters you pass, it's not a good thing for maintenance to have to count the parameters to know which one to change. No sane library would let you pass 16 parameters as direct unnamed arguments to a function
enabling you to pass only the needed parameters (the other ones being default)
#Igor 's answer (or some variation) is the way to go. If you have to use the functions elsewhere, though (as #dystroy pointed out), then there is another possibility. Combine your parameters together into an object, and pass that object to the secondary functions.
function combineEm() {
// Get all parameters into an array.
var args = [].slice.call(arguments, 0),
output = {},
i;
// Now put them in an object
for (i = 0; i < args.length; i++) {
output["param" + i] = args[i];
}
return output;
}
From your main function, you can do:
function mainfunction(param1, param2, ..., param16) {
var params = combineEm(param1, param2, ..., param16);
var output = secondaryfunction(params);
// etc.
return output;
}
Edit: I just wanted to clarify that all of the proposed suggestions so far do work. They just each have their own trade-offs/benefits.
I tried just suggesting some changes to other answers, but ultimately I felt like I needed to just post my solution to this.
var externalFn = function(options) {
var str = options.str || 'hello world';
alert(str);
};
var main = function(options) {
var privateMethod = function() {
var str = options.str || "foobar";
alert("str: " + str);
};
// Bind a private version of an external function
var privateMethodFromExternal = externalFn.bind(this, options);
privateMethod();
privateMethodFromExternal();
};
main({ str: "abc123"});
// alerts 'str: abc123'
// alerts 'abc123'
main({});
// alerts 'str: foobar'
// alerts 'hello world'
It seems like the main point of the question is that the functions used by the 'main function' shouldn't have to keep having the options/context passed to them.
This example shows how you can use privateMethods inside the function
It also shows how you can take external functions (that you presumably use outside of main) and bind a private method version of them for use inside main.
I prefer using some sort of 'options' object, but that aspect isn't really that important to the question of scoping that the OP was really asking about. You could use 'regular' parameters as well.
This example can be found on codepen.
Here's an incredibly naughty solution, if you're interested in that sort of thing.
var f1 = function() {
var a = 1;
var _f2 = f2.toString().replace(/^function[^{}]+{/, '');
_f2 = _f2.substr(0, _f2.length - 2);
eval(_f2);
}
var f2 = function(a) {
var a = a || 0;
console.log(a);
}
f2(); // logs 0
f1(); // logs 1
It executes the contents of some external function entirely in the current scope.
However, this sort of trickery is almost definitely an indicator that your project is mis-organized. Calling external functions should usually be no more difficult than passing an object around, as dystroy's answer suggests, defining the function in-scope, as Igor's answer suggests, or by attaching some external function to this and writing your functions primarily against the properties of this. Like so:
var FunLib = {
a : 0,
do : function() {
console.log(this.a);
}
}
var Class = function() {
this.a = 1;
this.do = FunLib.do;
this.somethingThatDependsOnDo = function() {
this.a++;
this.do();
}
}
var o = new Class();
FunLib.do() // 0
o.do() // 1
o.somethingThatDependsOnDo(); // 2
o.do() // 2 now
Similarly, and possibly better-solved with a class hierarchy.
function BasicShoe {
this.steps_taken = 0;
this.max_steps = 100000;
this.doStep = function() {
this.steps_taken++;
if (this.steps_taken > this.max_steps) {
throw new Exception("Broken Shoe!");
}
}
}
function Boot {
this.max_steps = 150000;
this.kick_step_equivalent = 10;
this.doKick = function() {
for (var i = 0; i < this.kick_step_equivalent; i++) {
this.doStep();
}
}
}
Boot.prototype = new BasicShoe();
function SteelTippedBoot {
this.max_steps = 175000;
this.kick_step_equivalent = 0;
}
SteelTippedBoot.prototype = new Boot();
I have written some javascript that I would to encapsulate in a closure so I can use it elsewhere. I would like do do this similar to the way jQuery has done it. I would like to be able to pass in an id to my closure and invoke some functions on it, while setting some options. Similar to this:
<script type="text/javascript">
_snr("#canvas").draw({
imageSrc : someImage.png
});
</script>
I have read a lot of different posts on how to use a closure to do this but am still struggling with the concept. Here is where I left off:
_snr = {};
(function (_snr) {
function merge(root){
for ( var i = 1; i < arguments.length; i++ )
for ( var key in arguments[i] )
root[key] = arguments[i][key];
return root;
}
_snr.draw = function (options) {
var defaults = {
canvasId : 'canvas',
imageSrc : 'images/someimage.png'
}
var options = merge(defaults, options)
return this.each(function() {
//More functions here
});
};
_snr.erase = function () {};
})(_snr);
When ever I try to call the draw function like the first code section above, I get the following error, '_snr is not a function'. Where am I going wrong here?
EDIT
Here is what I ended up doing:
function _snr(id) {
// About object is returned if there is no 'id' parameter
var about = {
Version: 0.2,
Author: "ferics2",
Created: "Summer 2011",
Updated: "3 September 2012"
};
if (id) {
if (window === this) {
return new _snr(id);
}
this.e = document.getElementById(id);
return this;
} else {
// No 'id' parameter was given, return the 'about' object
return about;
}
};
_snr.prototype = (function(){
var merge = function(root) {
for ( var i = 1; i < arguments.length; i++) {
for ( var key in arguments[i] ) {
root[key] = arguments[i][key];
}
}
return root;
};
return {
draw: function(options) {
var defaults = {
canvasId : 'canvas',
imageSrc : 'images/someimage.png'
};
options = merge(defaults, options);
return this;
},
erase: function() {
return this;
}
};
})();
I can now call:
<script type="text/javascript">
_snr("#canvas").draw({
imageSrc : someImage.png
});
</script>
Because you declared _snr as an object and not a function. Functions can have properties and methods, so there's various ways to achieve what you want, for example one of them would be say...
_snr = function(tag) {
this.tag = tag;
}
_snr.foo = function() {
//Code goes here
}
You can also pass the outer context into a closure to hide your variables from accidentally polluting the global namespace, so like...
(function(global) {
var _snr = function(tag) {
this.tag = tag;
}
_snr.foo = function() {
//Code goes here
}
//export the function to the window context:
global._snr = _snr;
})(window);
window._snr('#tag').foo('wat');
Happy coding.
Because your _snr is an object, not a function. You have to call it like this:
_snr.draw({
canvasId: '#canvas',
imageSrc: 'someImage.png'
});
When you do _snr('#canvas') that is a function call which is why you're getting that error. _snr is an object with some methods attached to it such as draw() and erase(). The reason jQuery is able to pass arguments into the $ is because they return the $ as a function object which is why we're able to pass it various selectors as arguments.
You are going wrong at the first line _snr = {}
It needs to be
_snr = function(){
selector = arguments[0]||false;
//snr init on dom object code
return _snrChild;
}
Im on a mobile phone but when im on a pc I will maybe fix the whole code c:
Here you have a snr object and that has erase and draw methods. What you intend to do is to write a _snr function which will get an id and return a wrapper object. That returned object should have erase and draw methods. so you can do
var returnedObject = _snr("my_id");
returnedObject.draw("image.png");
I'm just trying to structure my Javascript better and wondering how to incorporate window.onresize into the returned object, like so:
var baseline = function(){
var tall, newHeight, target, imgl, cur, images = [];
return {
init: function(selector, target){
this.images = document.querySelectorAll(selector);
this.target = target;
this.setbase(this.images);
window.onresize = this.setbase(this.images);
},
setbase: function(imgs){
this.imgl = imgs.length;
if(this.imgl !== 0){
while(this.imgl--){
this.cur = imgs[this.imgl];
this.cur.removeAttribute("style");
this.tall = this.cur.offsetHeight;
this.newHeight = Math.floor(this.tall / this.target) * this.target;
this.cur.style.maxHeight = this.newHeight + 'px';
}
} else {
return false;
}
}
}
}();
Is this the way that people would do it, is this going to work? Thanks
EDIT:
Invoked like so:
window.onload = function(){
baseline.init('img', '24');
};
I would like it so that when the window is resized, baseline.init is called with the same params as the initial init function call...
Here's the main error
init: function(selector, target){
this.images = document.querySelectorAll(selector);
this.target = target;
this.setbase(this.images);
// This line says call setbase now and assign the result of that
// as the onresize handler
window.onresize = this.setbase(this.images);
},
Your this.images does not point to the var images = [] you've created. This is for when you're using protoype style objects. You should just use images in your functions.
Some of your variables look like they're only used in setBase, they should be local
Looking at your object, it's very hard to tell what it's supposed to do, sounds like you're wrapping code in an object just for the sake of wrapping it into an object. What does baseline mean?
Here's a better version of your code, you should read and understand http://www.joezimjs.com/javascript/javascript-closures-and-the-module-pattern/ and http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html so you can decide what pattern you want to use and how they actually work. You are mixing both patterns, even though you didn't intend to. The trick is that with the way you're writing it (module pattern) there's no need to use this in the code, they're actually local variables held be the module
var baseline = function(){
// Don't use "this.tall", just "tall" gets you the variable
// Class variables, are you sure you need them throughout the class
var tall, newHeight, target, imgl, cur, images = [];
// Different name for the parameter so it doesn't get confused with
// the class variables
function init(selector, pTarget) {
images = document.querySelectorAll(selector);
target = pTarget;
setBase();
// Since we're not using this, you
// can just reference the function itself
window.onresize = setBase
}
// Most JS developers name methods using camelCase
function setBase() {
imgl = imgs.length;
if(imgl !== 0){
while(imgl--){
cur = imgs[imgl];
cur.removeAttribute("style");
tall = cur.offsetHeight;
newHeight = Math.floor(tall / target) * target;
cur.style.maxHeight = newHeight + 'px';
}
// should you return true here? what does returning
// something even mean here?
} else {
return false;
}
}
// Return just the public interface
return {
init: init
setBase: setBase
};
}();