JavaScript: Implementing Callback Functions - javascript

This is a three part question.
In the code shown below, whenever I execute the functions (walk, run, crawl) I am observing that it is displaying the output for the method distance_travelled in a cumulative manner:
Trey says thank you
Trey walked a distance of 3
Trey ran a distance of 13
Trey crawled a distance of 16
Trey ran a distance of 26
I would like to ensure that each function calculates the distance by considering the method distance_travelled to be initialized to 0.
My second question is related to the callback function.
I am trying to create another property/method called doSomething() and have this method return a random function back (walk, run, crawl).
For example if I execute the following code:
var returned_function = person.doSomething();
returned_function();
It should execute one of the three methods. I have managed to execute the method run(). However, when I run the code in my browser, the alert pop up message displays undefined. Also, I encounter the same issue as in my first question. It calculates distance_travelled in a cumulative manner. How can I solve this?
My third question. I am trying to add a new method called 'fly' to the person object. The 'fly' method takes two functions as arguments.
I have to give a 30% chance for the person to fly. The function fly method should execute if the person is successfully able to fly (30% chance that this can happen). The second function should execute if the person is NOT able to fly (70% chance this would happen).
How can I implement this functionality into my code? Can someone suggest how to approach this problem?
<script type="text/javascript">
var person = new Object();
person.name = "Trey";
person.distance_travelled = 0;
person.say_name = alert(person.name);
person.say_something = function(xyz) {
document.write(person.name + " says " + xyz + '<br>');
}
person.say_something("thank you");
person.walk = alert(person.name + " is walking");
function walk(){
person.distance_travelled +=3;
document.write(person.name + " walked a distance of " + person.distance_travelled + '<br>');
}
walk();
person.run = alert(person.name + " is running");
function run(){
person.distance_travelled +=10;
document.write(person.name + " ran a distance of " + person.distance_travelled + '<br>');
}
run();
person.crawl = alert(person.name + " is crawling");
function crawl(){
person.distance_travelled +=3;
document.write(person.name + " crawled a distance of " + person.distance_travelled + '<br>');
}
crawl();
person.doSomething = function(abc){
alert(run());
}
var returned_function = person.doSomething();
returned_function();
</script>

First of all:
person.walk = alert(person.name + " is walking");
probably does nothing like what you think it would (because I can't ever think a line like that might make sense).
Your first question is trivial. If you want to output 3, just output 3, not distance_travelled.
Second question:
var activities = ['run', 'walk', 'crawl'];
person.doSomething = function() {
var randomActivity = activities[Math.floor(Math.random() * activities.length)];
return function() {
this[randomActivity]();
}
}
var personDoActivity = person.doSomething();
personDoActivity();
or
person.doSomething = function() {
var activities = [this.run, this.walk, this.crawl];
var randomActivity = activities[Math.floor(Math.random() * activities.length)];
return randomActivity;
}
var doActivity = person.doSomething();
doActivity.call(person);
Third question (and I'm changing it from object-oriented to procedural because you're not using OO correctly, anyway):
function maybeFly(fly, noFly) {
if (Math.random() < 0.3) {
return fly();
} else {
return noFly();
}
}

Because I still can't comment on answers -.-
#Amadan
the second version of doSomething can maybe be even nicer using .bind()
person.doSomething = function() {
var activities = [this.run, this.walk, this.crawl];
var randomIndex = Math.floor(Math.random() * activities.length);
return activities[randomIndex].bind(this);
}
var doActivity = person.doSomething();
doActivity();
Also worth noting that it is better to use, and more in the spirit of javascript to write
var person = {};
instead of
var person = new Object();

Related

Nested function as method in javascript

I'm trying hard to understand basic concepts of javascript. The code below seems to be working fine if I use only "gear += 1" in line 8 below, but I cannot understand why is this not working when I'm using "this.gear += 1". It gives result as NaN. Thank you.
(function bike(speed, tank, gear) {
var i = {};
i.speed = speed;
i.tank = tank;
i.gear = gear;
i.addgear = (function() {
// works fine with "return gear+= 1" Why not with "this"?
return this.gear += 1;
})();
console.log("mybike", i);
})(120, 12, 5);
There are many ways to achieve what you're looking for, including the class keyword from ES2015 and up or the prototype system that underlies it. Here's a very simple sample:
function bike(speed, tank, gear) {
return {speed, tank, gear, addGear: function() {return this.gear += 1}}
}
const myBike = bike(120, 12, 5)
console.log(myBike);
myBike.addGear();
console.log(myBike)
Yours doesn't work for several reasons. First of all, you never return anything out of your outermost function. Secondly, you create and immediately execute a function whose output then becomes your addGear value. The simplest fix to your code would be something like this:
function bike(speed, tank, gear) {
var i = {};
i.speed = speed;
i.tank = tank;
i.gear = gear;
i.addgear = function() {
return this.gear += 1;
};
return i;
}
That would be equivalent to what I wrote above.

How to get Javascript object from HTML element

I have 3 "dice" objects created from this custom constructor:
function Dice() {
this.value = 0;
this.keep = false;
this.roll = function() {
this.value = Math.floor(Math.random()*6)+1;
};
}
Then, inside function rollOnce(), I have 3 HTML buttons inside a document.getElementById("paragraph1").innerHTML command that will display each dice's value as follows:
function rollOnce() {
(...)
document.getElementById("paragraph1").innerHTML =
'<button id="diceOne" class="unkept" onclick="keepDice(this.id)">'+dice1.value+'</button> ' +
'<button id="diceTwo" class="unkept" onclick="keepDice(this.id)">'+dice2.value+'</button> ' +
'<button id="diceThree" class="unkept" onclick="keepDice(this.id)">'+dice3.value+'</button> ';
}
Now, function keepDice(diceId) will set attribute class="kept" for each dice/button that has been clicked.
The next thing I want to do is to know which dice variable (dice1, dice2, dice3) has been clicked (in order to keep their value by doing diceN.keep = true;. Because after that there will be another round of the game in which only those dice which are "unkept" will get another diceN.roll() call. But my knowledge is still very limited and I only know how to access (HTML only) elements by using document.getElementsBy(...) (this is the HTML DOM, right? I'm currently learning this at W3Schools).
I have not yet learned about jQuery, AngularJS and all the other cool webdev stuff. So if it is possible to answer using only Javascript it would be much appreciated (even if other libs would make it easier! It's a bonus if there are alternative solutions and I would be happy to learn too!). Is this possible at all?
Thanks in advance,
Maybe something like class="kept-'+dice1.keet+'" onclick="keepDice(1)"
then
function keepDice(index){
dices[index].keep = true;
turns--;
if (turns > 0) {
rollOnce()
}
}
Try this:
function keepDice(id) {
var whichDice;
switch(id) {
case 'diceOne':
whichDice = dice1;
break;
case 'diceTwo':
whichDice = dice2;
break;
case 'diceThree':
whichDice = dice3;
break;
}
whichDice.keep = true;
}
If you stored your dice in an associative array like this:
dice['diceOne'] = new Dice();
dice['diceTwo'] = new Dice();
dice['diceThree'] = new Dice();
you would create the buttons almost the same way
<button id="diceOne" class="unkept" onclick="keepDice(this.id)">dice["diceOne"].value</button>
you could then write your dice function like this
function keepDice(id)
{
dice[id].keep = true;
document.GetElementById(id).setAttribute("class","kept");
//...
}
I came back to this again and realised there's a better way. It's quite a different approach than what you've got so far, but let me explain...
I know your question title is "How to get Javascript object from HTML element" but my answer better serves the question "How to get HTML element from Javascript object" and also better solves the problem you're facing.
First, I set the stage by creating a container element #paragraph1 and a "Roll Once" button which runs the rollOnce() function
<p id="paragraph1"></p>
<button onclick="rollOnce()">Roll Once</button>
Then I create the Dice() Object which takes a parameter - this parameter is the id of the element we wish to use as a container. We must wait for the HTML to load before we can find that container because until then, it simply doesn't exist yet. That's why I have bound a function to the document.onreadystatechange event.
So when the HTML has loaded and the document is ready, I initialise the Object, storing it in a var and the Object has all the required functions built-in for managing it's button.
function Dice(container) {
this.button = document.createElement("button");
this.button.innerHTML = 0;
document.getElementById(container).appendChild(this.button);
this.button.addEventListener('click', function() {
this.className = 'kept';
});
this.roll = function() {
if(this.button.className != 'kept') {
this.button.innerHTML = Math.floor(Math.random()*6)+1;
}
}
}
var dice1;
var dice2;
var dice3;
document.onreadystatechange = function () {
if(document.readyState == "complete") {
dice1 = new Dice("paragraph1");
dice2 = new Dice("paragraph1");
dice3 = new Dice("paragraph1");
rollOnce();
}
}
function rollOnce() {
dice1.roll();
dice2.roll();
dice3.roll();
}
Fully working demonstration is here: http://codepen.io/anon/pen/groEmg
Edit: If you want to get the values of the dice later, you can access the Objects' properties like so: dice1.button.innerHTML
You need to keep track of what has been kept and what has not been kept. It would be useful to hold all the dice functionality inside the dice class. every time you run rollOnce() you must also represent the kept/unkept state in the className.
Here's an example including what I gather is your current initialisation - define var dice then define rollOnce() then run rollOnce()
function Dice() {
this.value = 0;
this.kept = false;
this.roll = function() {
if(!this.kept) this.value = Math.floor(Math.random()*6)+1;
};
this.keep = function(id) {
this.kept = true;
document.getElementById(id).className = 'kept';
}
}
var dice1 = new Dice();
var dice2 = new Dice();
var dice3 = new Dice();
function rollOnce() {
dice1.roll();
dice2.roll();
dice3.roll();
document.getElementById("paragraph1").innerHTML =
'<button id="diceOne" class="'+(dice1.kept?'kept':'keep')+'" onclick="dice1.keep(\'diceOne\')">'+dice1.value+'</button> ' +
'<button id="diceTwo" class="'+(dice2.kept?'kept':'keep')+'" onclick="dice2.keep(\'diceTwo\')">'+dice2.value+'</button> ' +
'<button id="diceThree" class="'+(dice3.kept?'kept':'keep')+'" onclick="dice3.keep(\'diceThree\')">'+dice3.value+'</button> ';
}
rollOnce();
I've made it pass an ID to Dice.keep(id) just to have a live update of the DOM element which represents this Object variable.
Some clarification on the classnames since you're a beginner: I used ternary logic operators to quickly perform an IF THEN ELSE
So the part that says dice1.kept?'kept':'keep'
Actually means IF dice1.kept THEN 'kept' ELSE 'keep'
You can put a blank '' instead of 'keep' if you like since I don't think it's being used (but you might use it for CSS). Of course, there is plenty of room for improvement all over this code, but I wanted to keep it as similar to your sample code as possible. In fact, the first thing I would do is probably change the onclick to this: onclick="dice1.keep(this)" and then change your object like:
this.keep = function(button) {
this.kept = true;
button.className = 'kept';
}
http://codepen.io/anon/pen/MyrxyX
Edit: here's a slightly modified version where the Dice() object is agnostic to the DOM but still provides all the relevant data: http://codepen.io/anon/pen/MyrxbB

Why is my for loop freezing?

It looks like my for loop is looping the last object parsed into all fields.
http://codepen.io/anon/pen/EKxNaN
This is the actual code I am using, I built something kind of similar for codepen since I cannot request JSON from the actual source on codepen.
var championMasteryPHP = "https://api.myjson.com/bins/xked";
$.getJSON(championMasteryPHP, function (json) {
for (var i = 0; i < json.length; i++) {
var champID = json[i].championId;
var champLevel = json[i].championLevel;
var pointstonextlevel = json[i].championPointsUntilNextLevel;
var championInfo = "http://example.com/champInfo.php?champid=" + champID;
$.getJSON(championInfo, function (json2) {
var champName = json2.name;
var champTitle = json2.title;
$('#champ').append("<li>ID: " + champID + " | Name: " + champName + " | Level: " + champLevel + " | Points to Next Level: " + pointstonextlevel + "</li>");
});
};
});
Long story short, what I am trying to achieve would look like this.
But for some reason, this is what I get instead.
The right names, but the other variables are the very last variable in the listing.
Is there a better way to do this? Am I doing something terribly wrong?
Thanks.
You are using Asynchronous Process inside a javascript for loop more info here
You can modify to use self executing function, so it will work
var championMastery = "https://api.myjson.com/bins/xked";
$.getJSON(championMastery, function (json) {
for (var i = 0; i < json.length; i++) {
(function(obj){
var champID = obj.championId;
var champLevel = obj.championLevel;
var pointstonextlevel = obj.championPointsUntilNextLevel;
var championInfo = "http://example.com/champInfo.php?champid=" + champID;
$.getJSON(championInfo, function (json2) {
var champName = json2.name;
var champTitle = json2.title;
$('#champ').append("<li>ID: "+champID+" | Name: " +champName+ " | Level: " +champLevel+ " | Points to Next Level: " +pointstonextlevel+ "</li>");
});
})(json[i])
};
});
A very good article which I came across recently. Detailing about the Javascript Scope ans Closures . This is a must know things for coding in javascript, Jquery. And the part where there is an explanation to this above problem is look for the topic under The Infamous Loop Problem
Now coming to the problem. Your code should actually look like
$.getJSON(championInfo, function (json2) {
(function(){
var champName = json2.name;
var champTitle = json2.title;
$('#champ').append("<li>ID: "+champID+" | Name: " +champName+ " | Level: " +champLevel+ " | Points to Next Level: " +pointstonextlevel+ "</li>");
})()
});
Note the change where I have added the self executing function. The problem you got the weird output with the same outputs for all the function is because.
Your function Inside the $.getJSON call back is just a function definition and the function is not executed at that moment. By the time your first getJSON hits its call back your for loop is complete, And the final value in the variables are of the last loop and hence when your first getJSONhits its callback it displays the values of the last loop.
To make it more simple. Write this in your console window.
function alert1(){ alert("I am one!!");}
And now call / execute the function by doing
alert1();
You will get a alert saying "I am one!!"
Now add this to the console
function alert1(){ alert("I am one, But overritten!!");}
And then try out calling it. The out put would be "I am one, But overritten!!", So the function actually gets overwritten and that's what is happening in the for loop. The last function is the one which is available for all the callbacks.

Accesing function within function JavaScript

I got this piece of code below which is not DRY. What i want to do is to cut it,so everything below var = text would be used only once not twice.
My concept is,to close these two functions in bigger function (e.g. guess()) and keep trimmed correctGuess() and incorrectGuess() within it.
Now here's the question,how can I call such nested function as describe above from outside scope. I was thinking about smth like: guess().correctGuess() which is obviously wrong but I wanted to share a concept.
Additionally, when e.g. correctGuess() would be called, is rest of the commands within our main guess() function would be executed?
function correctGuess(i) {
totalScore++;
questionNumber++;
var text = "Correct!";
var updatePage = ['<div id="answerDiv">' +
'<h1>' + text + '<h1>' +
'<h2>Total Score: ' + totalScore + '</h2></div>'
];
mainContent[html](updatePage);
$('#answerDiv')[fadeIn]("slow");
$('#answerDiv').append('<button id="nextButton">Next Question</button>');
$('#nextButton').on('click', function() {
if (questionNumber == allQuestions.length && totalScore <= 4) {
results()
} else {
question(questionNumber)
}
})
};
var incorrectGuess = function(i) {
totalScore--;
questionNumber++;
var text = "Wrong!";
var updatePage = ['<div id="answerDiv">' +
'<h1>' + text + '<h1>' +
'<h2>Total Score: ' + totalScore + '</h2></div>'
];
mainContent[html](updatePage);
$('#answerDiv')[fadeIn]("slow");
$('#answerDiv').append('<button id="nextButton">Next Question</button>');
$('#nextButton').on('click', function() {
if (questionNumber == allQuestions.length && totalScore <= 4) {
results();
} else {
question(questionNumber);
}
});
};
http://www.w3schools.com/js/js_objects.asp
From your question it seems like you aren't very familiar with object notation. Read up on the above link and then try to create a js "guess" object with 2 member functions. Correct and Incorrect guess.
You need to use the this keyword.
function guess(){
/* do stuff here for guess() */
this.correct = function(){
/* Do stuff for correct */
}
this.wrong = function(){
/* Do stuff for wrong */
}
return this;
}
Because you returned this you can now access the correct() and wrong() functions using:
guess().correct();
// AND
guess().wrong();
Note that whatever code you write inside guess() and outside the two nested functions will also be called every time you call guess().correct() or guess().wrong()
If you do not want any particular code to execute every time they "guess" regardless of right or wrong then I would suggest just storing the correct() and wrong() functions in an object literal.
var guess = {
correct: function(){
// Code for "correct" here
},
wrong: function(){
// Code for "wrong" here
}
}
And then you can access them using
guess.correct();
// AND
guess.wrong();

Javascript object get code as string

First off, I am sorry if this is a duplicate, but every time I googled for 'object' and 'code' I got tutorial pages.
I want to know if there is any easy way to get the code associated with an object. Something like
function A(){
this.name = 'Kaiser Sauze';
}
a = new A();
console.log(a.displayCode());
//OUTPUT
"function A(){ this.name = 'Kaiser Sauze';}"
I want to be able to view the code, modify it and reload the function, all from within the browser. I wanted to know if there was some way to do this, or if I have to prime the pump by doing something like this:
function A(){
this.name = 'Kaiser Sauze';
this.code = "function A(){ this.name = 'Kaiser Sauze';}"
}
then every time the user loads up the text editor to view this.code I connect the onchange to update this.code.
EDIT
turns out yankee suggested a simple solution to this
function A(x){
this.x = x ;
}
console.log(A.toString());
//OUTPUT
"function A(x){
this.x = x ;
}"
but in my implementation the variable 'x' can be a function (actually a complicated object with variables, functions and sub objects which I mix in via a call to dojo.mixin), so what I really want is to know the code when instantiated, something like so
function A(x){
this.x = x ;
}
var a = new A(function(){/*DO SOMETHING*/);
console.log(a.toString());
//OUTPUT
"var a = new A(function(){/*DO SOMETHING*/);"
but, as most of you already know, all that gets output is something like "Object". I have almost found a way around this, by putting the initialization in a function like so
function A(x){
this.x = x ;
}
function _A(){
var a = new A(function(){/*DO SOMETHING*/);
}
console.log(_A.toString());
//OUTPUT
"function _A(){
var a = new A(function(){/*DO SOMETHING*/);
}"
but that is confusing, and then I have to go in and start parsing the string which I do not want to do.
EDIT: The reason I ask all of this is b/c I want to make code that is both dynamically executable and highly modular. I am dealing with the canvas. I want the user to be able to click on a, for example, rectangle, view its code, and modify and then load/execute it. I have a series of rules but basically I have a shape class and everything that defines that shape (color, transparency, fills, strokes...) has to get passed as a parameter to the object cosntructor, something like:
rect = new Shape({color : 'rgba(0,0,0,1)' ,
x : 0 ,
y : 0 ,
w : 100 ,
h : 100 ,
draw : function() {ctx.fillStyle = this.color;
ctx.fillRect(this.x,this.y,this.w,this.h);
}
});
This way the code is automatically modular, I don't have to worry about the color being defined at the top of the page, and then the height being defined half way down the page, and so on. Now the only thing I need is to somehow, pass as a parameter, the entire above string representation of the initialization. I could wrap it in a function and call toString on that, like so
function wrapper(){
rect = new Shape({color : 'rgba(0,0,0,1)' ,
x : 0 ,
y : 0 ,
w : 100 ,
h : 100 ,
draw : function() {ctx.fillStyle = this.color;
ctx.fillRect(this.x,this.y,this.w,this.h);
},
code : wrapper.toString()
});
}
but then there are two problems. 1) I have to manually remove the function wrapper() and trailing } as well as moving every line to the left by one tab. 2) there is no guarantee that a user will remember to include the wrapper function as it is totally unecessary for purposes of drawing. I am trying to think of a way where the wrapper would seem natural, but I can't think of any. But then again I haven't slept in over 30 hours.
OK... Reviewing again... I think that's what you want ;-).
>>> function A() {this.name ="foo";}
undefined
>>> A.toString()
"function A() {this.name ="foo";}"
Refer to code snippet below:
function A() {
this.name = 'Kaiser Sauze';
}
a = new A();
console.log(a.constructor.toString());
// output
// "function A(){
// this.name = 'Kaiser Sauze';
// }"
When you do new A(), function A becomes the constructor of object a. Thus, you can reference function A via the constructor property of object a.
Read more about Javascript constructor on MDN.
Edit: added pretty-printing.
You could JSON.stringify() the argument of the constructor, if it is JSON-compatible. Here is a toString() function that builds on this idea, but with a slightly generalized version of JSON.stringify() that accepts stringifying functions:
function Shape(x){
this.x = x;
}
Shape.prototype.toString = function() {
function stringify(data, prefix) {
function unicode_escape(c) {
var s = c.charCodeAt(0).toString(16);
while (s.length < 4) s = "0" + s;
return "\\u" + s;
}
if (!prefix) prefix = "";
switch (typeof data) {
case "object": // object, array or null
if (data == null) return "null";
var i, pieces = [], before, after;
var indent = prefix + " ";
if (data instanceof Array) {
for (i = 0; i < data.length; i++)
pieces.push(stringify(data[i], indent));
before = "[\n";
after = "]";
}
else {
for (i in data)
pieces.push(i + ": " + stringify(data[i], indent));
before = "{\n";
after = "}";
}
return before + indent
+ pieces.join(",\n" + indent)
+ "\n" + prefix + after;
case "string":
data = data.replace(/\\/g, "\\\\").replace(/"/g, '\\"')
.replace(/\n/g, "\\n").replace(/\r/g, "\\r")
.replace(/\t/g, "\\t")
.replace(/[\x00-\x19]/g, unicode_escape);
return '"' + data + '"';
default:
return String(data).replace(/\n/g, "\n" + prefix);
}
}
return "new Shape(" + stringify(this.x) + ")";
};
var rect = new Shape({color : 'rgba(0,0,0,1)' ,
x : 0 ,
y : 0 ,
w : 100 ,
h : 100 ,
draw : function() {ctx.fillStyle = this.color;
ctx.fillRect(this.x,this.y,this.w,this.h);
}
});
console.log(rect.toString());
The output is:
new Shape({
color: "rgba(0,0,0,1)",
x: 0,
y: 0,
w: 100,
h: 100,
draw: function() {
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.w, this.h);
}
})
I can't believe no one suggested this (I apologize if this answer is somewhere in between the lines). I didn't think of it because at the time of development, all my work was clientside. All I really have to do is load the code once with Ajax as javascript. Once it is loaded and an object created, I load it again as a string and assign it to a variable in the object.
Here is another solution that might work (using yankee's example). I am however unsure what happens if A already exists? Perhaps you should do a "delete(A);" before saving it in the storage.
// Create A
// function A() {this.name = "foo";}
var x = 'function A() {this.name = "foo";}'; // Store function to variable using A.toString();
// Save x in storage
// -- Page reload --
// Load and eval x from storage
eval(x);
var a = new A(); // Use A
alert(a.name);
function dumpObject(obj)
{
var output = "";
for (var i in obj)
{
var msg = i + "= " + obj[i];
output += msg + "\n";
}
return output;
}
var myObject = {
myName: 'Daniel',
get_name: function()
{
return this.myName;
}
}
alert( dumpObject(myObject) );
//this will output:
//
// myName= Daniel
// get_name=function()
// {
// return this.myName;
// }
Here is my fiddle for that:
http://jsfiddle.net/DanielDZC/vXrQf/
I wouldn't recommend using on a production server, only for testing and debugging, but there is a method named toSource() which returns the source of a function as a String:
function add(a, b) {
return a + b;
}
console.log(add.toSource());
Outputs:
function add(a, b) { return a + b; }
Available on JS Fiddle: http://jsfiddle.net/IQAndreas/dP453/1/
Note that Mozilla has marked this method as non-standard (which if you read the details means "Only works in FireFox").
Sounds like you're looking for Reflection and/or Introspection support. I'm not sure where the other major engines are at in this regards but SpiderMonkey's Parser API was recently referenced in an article on Extension Introspection with Chrome Privileges.

Categories