I am working on learning JavaScript composition over inheritance and I am struggling with a few concepts. One being, the game presents users with a random number of dogs, they are then prompted to enter how many there are.
If they get it correct, they score a point and are then presented with another number of dogs.
The thing I can't work out is how to generate new dogs each time. The below code is the simplified code setup:
var dog = function dog(state) {
return {
create: function create() {
console.log('Create the dogs');
this.dogIsCreated();
},
dogIsCreated: function dogIsCreated() {
console.log('How many dogs do you see?');
}
}
}
var questionOne = dog({number: 3}).create();
Once they have chosen the right number, i need to effectively call:
var questionTwo = dog({number: 6}).create();
The number itself will just be a call to a random number generator, but how would I call questionTwo automatically? I have no idea where to even begin!
Many thanks!
The action of 'getting it correct' occurs because of an event. You need to hook into this event, determine true/false, and when correct call dog({number: x}).create();.
If your requirement is more complex than this, please clarify your question. Thanks.
Approach this using array should provide better accessibility.
var dog = function dog(state) {
return {
answer: state.number,
create: function create() {
console.log('Create the dogs');
this.dogIsCreated();
},
dogIsCreated: function dogIsCreated() {
console.log('How many dogs do you see?');
}
}
var currentQuestion = 0;
var question = [];
function nextQuestion() {
if (currentQuestion > 0) {
//to access the last question use question[currentQuestion] e.g. question[currentQuestion].answer
}
question.push(dog({number: 6}).create());
currentQuestion++;
}
Related
In my case, I'm using the Phaser framework.
So in this example I'm extending the Group class of phaser. Every 'actor' class (Sprite, Group, ...) calls upon the update() prototype every few miliseconds.
My idea was to extend this function only when the application runs on a desktop (so not on a phone).
for example:
var MousePointer = function (game, parent, name) {
Phaser.Group.call(this, game, parent, name);
this.init();
};
MousePointer.prototype = Object.create(Phaser.Group.prototype);
MousePointer.prototype.constructor = MousePointer;
MousePointer.prototype.init = function () {
// ... init
};
MousePointer.prototype.update = function () {
// Do something when on desktop
};
I can't possibly use an if clausule in the update() function to check whether the player is on dekstop/tablet/phone. So is there a way to actually override the prototype on initialisation?
for example (pseudocode):
if(onPhone)
MousePointer.prototype.update = parent.prototype.update;
else
MousePointer.prototype.update = this.update;
Well, you've kind of already written the answer for yourself, haven't you? This code (not inside the init method).
if(onPhone) {
MousePointer.prototype.update = function(){//Phone implementation};
} else {
MousePointer.prototype.update = function(){//Other implementation};
}
I advise against starting off with the "regular" function and then potentially overriding it, since you're just declaring it for nothing.
I think a better way to do this would be to write two different classes that shares the same parent, and then write different update() implementations for them. Then you can just do something like:
if(phone) {
var obj = new PhoneMousePointerObject();
} else {
var obj = new DesktopMousePointerObject();
}
// ... later
obj.update()
I'm reading and watching Tutorials about Meteor since 1-2 Weeks. I've learned about how to structure a meteor app regarding server and client side code, accounts, security etc.
What i could not figure out:
Where do i put the calculation logic properly?
For example:
A user puts data in a form and the data is saved in the database. Depending on this input data i want to do several calculations by putting the data through lets say a chaining of around 20 Methods, and finally display some results.
At the moment i have all of these Methods inside the file where the Template.displayResults.helper is.
When i put them in another file they don't get recognized, i think because of the wrapper Meteor puts around.
Example: I have a collection of DIY projects and each of the projects has a field with an array of utilities that are neccessary for the project.
Projects = new Mongo.Collection('projects');
/*
exampleProject = {
"name": "Kitchen table",
"utilities": ["Hammer", "Glue"]
}
*/
I want to display all possible DIY projects depending on the utilities the user has checked.
The UI has a group of checkboxes via the user can select a bunch of utilities he wants to use.
These values are saved in a collection.
Utilities = new Mongo.Collection('utilities');
/*
exampleUtility = {
"name": "Hammer",
"checked": true
}
*/
Then i want to calculate the possible Projects...
Template.displayResults.helpers({
projectsPossible: function () {
var utilitiesCheckedDB = Utilities.find({
checked: true
}).fetch();
var projectsAll = Projects.find().fetch();
return projectsPossible(utilitiesCheckedDB, projectsAll);
}
});
// Returns an array of all possible projects depending on the selected utilities
function projectsPossible(utilitiesCheckedDB, projectsAll) {
var result = [];
_.each(projectsAll, function (project) {
if (project.utilities.length === _.intersection(project.utilities, checkedCheckboxesList(utilitiesCheckedDB)).length) {
result.push(project);
}
});
return result;
}
// Returns an array of all checked utilities in the current checkbox database
function checkedCheckboxesList(checkedCheckboxesDB) {
var result = [];
_.each(checkedCheckboxesDB, function (checkbox) {
result.push(checkbox.name);
});
return result;
}
The question is: There are more methods like "projectsPossible" and "checkedCheckboxesList". Where do i put these methods to get a good structure?
Thanks in advance!
Vin
If you want to register global helpers, just use Template.registerHelper(name, function), for instance:
Template.registerHelper('projectsPossible', function() {
var utilitiesCheckedDB = Utilities.find({
checked: true
}).fetch();
var projectsAll = Projects.find().fetch();
return projectsPossible(utilitiesCheckedDB, projectsAll);
});
If you want to make the functions projectsPossible(utilitiesCheckedDB, projectsAll) or checkedCheckboxesList(checkedCheckboxesDB) accessible from other (client) files, you can make them global. For example:
projectsPossible = function(utilitiesCheckedDB, projectsAll) {
var result = [];
_.each(projectsAll, function(project) {
if (project.utilities.length === _.intersection(project.utilities, checkedCheckboxesList(utilitiesCheckedDB)).length) {
result.push(project);
}
});
return result;
};
You can make model classes, using the transform option for collections. For an ES5 example, see the docs: http://docs.meteor.com/#/full/mongo_collection
Also, you have to make that model class or function global by not using var.
(function() {
foo = function foo() {
alert("fooh")
}
})()
In the above example, without foo =, the foo function would only be visible inside its own file because of the wrapper.
I am creating a random photo365 challenge list generator using javascript. I have a list of 365 different function which come up with a different assignment name/page link (this probably isn't the best way to do it, but it works)
It works as it's supposed to, it does call 365 functions and puts them in a list...
But what I'd like to do is prevent repeats. (Please note, the code below doesn't have all the 365 functions listed)
I have searched on stack overflow, and I have come across a variety of methods of preventing repeats. But any time I try to add the new code it, I can't get it to work.
I'm really not that skilled in javascript, so any guidance you could provide would be extremely appreciated...
Noel
//Create a new To-Do
function randomFrom(array) {return array[Math.floor(Math.random() * array.length)];}
function randomCreate() {
var func = randomFrom([createNew365ToDo,
createNew365ToDoBulb,
createNew365ToDo2,
createNew365ToDoShallow,
createNew365ToDoWide,
createNew365ToDoLenses,
createNew365ToDoMacro,
createNew365ToDoAToZ]);
(func)();
}
function createNew365ToDoList()
{
deleteAll365Rows();
for (var p = 0; p < 365; p++) {
{
randomCreate();
}
}}
I would do something like this:
//are arrays passed by reference? I don't remember, so let's just make it available to everything to demonstrate
var fnArray = [createNew365ToDo, createNew365ToDoBulb, createNew365ToDo2, createNew365ToDoShallow, createNew365ToDoWide, createNew365ToDoLenses, createNew365ToDoMacro,createNew365ToDoAToZ];
function randomFunction() {
//get a random index from the list
var index = Math.floor(Math.random() * fnArray.length);
//save that function to fn, and REMOVE it from the list
var fn = fnArray.splice(index, 1);
//return that function - now, when randomFunction() gets called again, you won't ever
//return the same function since it's no longer in the list
return fn;
}
function callRandomFunction() {
var func = randomFunction();
(func)();
}
I have a class called Room, with an array containing all the Player entities as one of its properties,
players = [];
In the Room class is a method that only returns the players who actually competed in the round.
// below method is called by the room's timer
var getPlayersWhoFinished = function() {
playersWhoFinished = [];
for (i = 0; i < players.length; i++) {
if (players[i].isFinished()) {
playersWhoFinished.push(players[i]);
};
};
return playersWhoFinished;
}
So I know that I could just leave the above in the Room class as is, but I already have three other functions with more complex mapping, in an already large class (300+ lines).
I don't understand how to encapsulate these sort of methods into other classes, as they're so closely related to the Room class and all the the Room reference to be sent to the appropiate users.
Modifying the above code and slotting it into Player class would sort of make sense to me, but the only way I can think of getting this to work is using a static method and sending the room object to it.
// players is now a member of the Player class
Player.getPlayersWhoFinished = function(room, players) {
playersWhoFinished = [];
for (i = 0; i < players; i++) {
if (players[i].getRoom() == room) {
playersWhoFinished.push(players[i]);
}
}
return playersWhoFinished;
}
Anyway, this seems cumbersome and inefficent to me. I've really been struggling to figure out how to make my Room class lithe as possible.
Consider splitting logic into Objects and Collections. It is similar to what backbone offers (Model, Collection).
As collections logic is usually specific to objects it contains, but have some shared functionality as well (simple iterations, filters and so on), you can create generic Collection, and then through Inheritance add more methods in order to fit your needs of that specific Object it stores.
So you would have your room:
function Room() {
// ..
this.players = new PlayerCollection();
// ..
}
For collection I've added some 'bonus' methods, so it would look like:
function Collection() {
this.list = [ ];
this.length = 0;
}
// adds item
Collection.prototype.add = function(item) {
this.list.push(item);
this.length = this.list.length;
}
// removes by index
Collection.prototype.remove = function(index) {
this.list.splice(index, 1);
this.length = this.list.length;
}
// finds one item based on filter function, and triggers callback with item and index
Collection.prototype.findOne = function(fn, callback) {
for(var i = 0, len = this.list.length; i < len; ++i) {
var result = fn(this.list[i]);
if (result) {
return callback(this.list[i], i);
}
}
return callback(null, -1);
}
// filters off
Collection.prototype.filter = function(fn) {
return this.list.filter(fn);
}
Then you would define PlayerCollection, that will have extra method just to filter off players who is finished:
function PlayerCollection() {
Collection.call(this);
}
// some inheritance here
PlayerCollection.prototype = Object.create(Collection.prototype);
PlayerCollection.prototype.constructor = PlayerCollection;
// returns list of finished players
PlayerCollection.prototype.finished = function() {
return Collection.prototype.filter.call(this, function(player) {
return player.isFinished();
});
}
You still can reuse that filter method, as it helps to create some bespoke queries.
Your room logic would look like:
var room = new Room();
// add some players to room
// ...
var finishedPlayers = room.players.finished(); // what you need
It looks clear and straight forward, as well keeps all collection logic away from Room, so you can simply reuse it all over your game code. And improving in one place - would improve it as a whole.
Dividing logic into abstracts like that, helps to scale your code and separate dependencies.
Bear in mind Browser support for filter and if you need -IE8, then get shim from here.
The getPlayersWhoFinished() method belongs to Room, which is the object that should track players. You also are performing a search in O(n) complexity every time you need to find finished players, which can be improved.
You could have a callback mean to be called each time a player finishes:
Player.prototype.onFinished = function() {
this.getRoom().addFinished(this);
}
And then manage a private array in Room containing all the finished players:
function Room() {
this._finishedPlayers = [];
}
Room.prototype.addFinished = function(player) {
this._finishedPlayers.push(player);
}
Room.prototype.getPlayersWhoFinished = function() {
return this._finishedPlayers;
}
As a side note, you should always declare variables with var, or else you will get them declared in the global scope (i.e. usually the window object).
I have this javascript function:
function files() {
var dropResult = false;
$('#button1').on('click', function() {
dropResult = true;
});
$('#button2').on('click', function() {
dropResult = false;
});
return dropResult;
}
files();
The dropResult variable must change after we click one of the buttons. How do I write it properly to make my function return the right value of dropResult variable?
I know, that it's about closures but I don't really understand how to fix this problem.
Thanks for help.
I believe you want
var files = (function () {
var dropResult = false;
$('#button1').on('click', function () {
dropResult = true;
});
$('#button2').on('click', function () {
dropResult = false;
});
return function () {
return dropResult;
};
})();
Demo at http://jsfiddle.net/gaby/9b7yK/
var dropResult = false;
$('#button1').on('click', function() {
dropResult = true;
});
$('#button2').on('click', function() {
dropResult = false;
});
function files() {
return dropResult;
}
Assuming all you need is to get the correct value for dropResult, the above code should work.
I will "extend" the answer of Gaby aka, but I think he is totally right. I will make only more specific in private and public methods. and how to access to them, and actually also bind the events to a specific button you can check the fiddle here [http://jsfiddle.net/qsDz6/][1]
HTML
<input type="button" id="button1" value="button 1" />
<input type="button" id="button2" value="button 2">
<input type="button" id="actualValue" value="Actual Value of _dropResult">
JS
var files = (function(__name){
var _name = __name;
var _dropResult = null;
/*Private */
function init(){
eventHandler();
}
function eventHandler(){
$(document).on("click","#button1", $.proxy($r.actionButton1,this));
$(document).on("click","#button2", $.proxy($r.actionButton2,this));
$(document).on("click", "#actualValue", $.proxy($r.dropResult,this));
}
/*Public */
var $r = {}; //will make public any method
$r.actionButton1 = function(){
_dropResult = true;
alert(_dropResult);
}
$r.actionButton2 = function(){
_dropResult = false;
alert(_dropResult);
}
$r.dropResult = function(){alert(_dropResult);}
init();
return $r;
})("files");
Happy coding
Update: Somehow this answer has been down-voted despite the fact that the most up-voted solution was posted at the same time, is equally elegant, and is logically equivalent. The other solution simply chooses to capture the local variable in a function closure rather than an object closure.
The responsibility of being a voter is to actually read and think about what these solutions do, rather than just voting for the answer provided by someone familiar or by the person with the highest reputation.
The responsibility that I have in answering is to only answer questions not for a popularity contest, but when (A) I know for certain a valid answer and am willing to take the time to explain and maintain that answer; or (B) for some discussion questions where there is nothing so clear-cut as the "answer," then only when I have encountered the issue many times in my experience and have something to say about it based on my actual experience.
For that reason, I am leaving my answer up (just as I have done in the past) even when someone in the community anonymously decides to downvote it without any explanation why.
Remember that the answers at Stack Overflow are intended to be a repository of useful solutions to useful questions, for the benefit of all programmers in the future. It is worthwhile to show two different approaches rather than a single one.
Yes, the other solution is elegant and demonstrates nicely capturing a local variable using an anonymous function closure. Yet, in my opinion, my solution is slightly better in the context of the purpose that Stack Overflow has, because this solution can be easily modified into a reusable function for creating many monitoring variables. The other solution would require a bit of deconvolution in order to make it useful for more than a single static instantiation of one monitoring function.
function files() {
var dropResult = {};
$('#button1').on('click', function() {
dropResult.result = true;
});
$('#button2').on('click', function() {
dropResult.result = false;
});
return dropResult;
}
var dropObject = files();
The variable dropObject is a "monitoring variable" that can be used anywhere in order to check the status of what you are monitoring (in this case, which alternative the user last specified by their most recent click on either button1 or button2.)
In code that uses the result from files() you can do this
if (dropObject.result) {
/* do something here that you want to do when the result is true */
} else {
/* do something here when the result is false */
}
I would suggest storing something more meaningful than true or false (what if you wanted to add a third button and then monitor which of the three had last been clicked, for example?).
Note: Here is how I would write a smaller, more efficient reusable monitoring function for my use (not hard-wiring any parameters or names inside the function) and apply it to this scenario:
function clickMonitor(ids) {
var i, f = function() { i = this; }; ids = ids.match(/(\S+)/g) || [];
for (i=0; i<ids.length; i++)
document.getElementById(ids[i]).onclick = f;
return function() { return i; };
}
This next part just creates a dropResult variable that would be
"plug and play" in place of your dropResult variable, except that you
would have to check to see if dropResult() is true or false
(function invocation) rather than just dropResult.
dropResult = (function() {
var x = clickMonitor('button1 button2');
return function() { return x().id == 'button1'; };
})();
In general, this is how you would use it (more than two button IDs can be passed to it, of course, if wanted):
getMostRecentClickedButton = clickMonitor('button1 button2');
Calling getMostRecentClickedButton() returns the entire button
object most recently clicked so that you can do something with it, like
make the font bold, etc., without needing to perform another intermediate
jQuery or JavaScript procedure.
I don't understand the need for this but one way would be
function files() {
files dropResult = false;
return files.dropResult;
}
$(document).on('click', '#button1', function() {
files.dropResult = true;
});
$(document).on('click', '#button2', function() {
files.dropResult = false;
});
files();