Good evening, If someone could help me , I would be glad.I am trying to reach some functions in my Car class. Firstly I am trying to assign inpSpeed input value to Car class function Drive and then I wanna print out to console all cars info when I press the button: btnRace and the problem is I dont really know how to call them , because everytime I call them it says:"undefined".
here is my code so far:
carsArray = [];
btnCarName.onclick = function(){
carsArray.push({/*obj.element1, obj.element2, obj.element3*/});
}
btnRace.onclick = function(){
for(j in carsArray)
{
console.log(Car(carsArray[j]));
}
}
function Car(name,speed)
{
this.carBrand = name;
this.speed = speed;
this.distance = 0;
this.Drive = function(time)
{
if(time > 0)
return this.distance = (this.speed * (time/10));
}
this.printData = function()
{
for(var i = 0; i < Car.length; i++)
{
console.log('Car brand: ' + this.carBrand);
console.log('Speed: ' + this.speed);
console.log('distance: ' + this.Drive());
console.log('---------------------------');
}
}
}
For the this keyword to work, you must instantiate Car() with the new keyword:
var toyota = new Car('toyota', 100)
console.log(toyota.speed);
There may however be a couple other issues. What exactly is expected from Car.length?
Related
I am trying to add multiple instances of different objects to another object's array. I'm having trouble however.
*Creates the player*
function Player(){
this.name = "";
this.status = "Alive";
this.primaryClass = null;
this.secondaryClass = null;
this.strength = 0;
this.stamina = 0;
this.mystica = 0;
this.health = 0;
this.primaryWeapon = null;
this.offHand = null;
this.accuracy = 0;
this.block = 0;
this.baseDamage = 0;
this.maxDamage = 0;
this.attackSpeed = 0;
this.shield = null;
this.armor = null;
this.armorRating = 0;
this.exp = 0;
}
*Creates the sword weapon*
function LongSword(){
this.name = "";
this.attackSpeed = 1;
this.baseDamage = 10;
this.maxDamage = 15;
this.durability = 100;
this.block = 5;
this.exp = 0;
}
*Creates the Long Sword skills*
function Stab(){
this.name = "Stab";
this.status = "Unlocked";
this.damage = 0;
this.damageModifier = 0.75;
this.cooldown = 5;
this.exp = 0;
this.desc = "Stabs your opponent for an additional " +parseInt(this.damageModifier * 100) +"% of your base damage.";
}
*Equips the Player weapon(s)*
Player.prototype.equipWeapon = function equipWeapon(main, offHand){
if(this.primaryClass.dualWield){
this.primaryWeapon = main;
if(offHand){
this.offHand = offHand;
this.baseDamage += (this.strength + (main.baseDamage + (offHand.baseDamage / 2))) / 10;
this.maxDamage += (this.strength + (main.maxDamage + (offHand.maxDamage / 2))) / 5;
this.attackSpeed += main.attackSpeed + (offHand.attackSpeed / 2);
this.block += main.block + offHand.block;
}
}
else{
this.primaryWeapon = main;
this.offHand = null;
this.baseDamage += (this.strength + main.baseDamage) / 10;
this.maxDamage += (this.strength + main.maxDamage) / 5;
this.attackSpeed += main.attackSpeed;
this.block += main.block;
}
if(!this.primaryClass.dualWield && offHand){
console.log("Your class can not wield dual weapons.");
}
}
*Equips the Weapon skills*
LongSword.prototype.skills = function skills(skill){
this.skills = [];
skill.damage = parseFloat((this.baseDamage / skill.damageModifier).toFixed(1));
this.skills.push(skill);
}
These objects construct the basic elements of what I'm trying to do. So when I go to instantiate each one,
var Robert = new Player();
Robert.equipWeapon(new LongSword());
Robert.primaryWeapon.skills(new Stab());
I am getting the results I want. However, if I were to try to add another instance of Stab() so that it looks like this
var Robert = new Player();
Robert.equipWeapon(new LongSword());
Robert.primaryWeapon.skills(new Stab());
Robert.primaryWeapon.skills(new Stab());
I get the TypeError: Robert.primaryWeapon.skills is not a function. Why would it work correctly once, but not a second time. The end result of which I'm trying to achieve is that if consoled out Robert.primaryWeapon.skills, I should see two instances of the Stab object.
There are two issues in your Longsword's prototype.
First, you are replacing your function with your storing skill array, which have the same name :
LongSword.prototype.skills = function skills(skill){
this.skills = []; //Overrides your function
...
Which leads to your error, Robert.primaryWeapon.skills is not a function, cause once you call it, it is an array indeed.
To fix it, just change the name of one of the function or of the array.
Secondly, you are initializing your skills array to an empty array each time you call the function, resetting it every time. You should initialize it in Longsword's protoype.
Here's a an example with these fixes (fiddle with it if you want):
function LongSword(){
this.skills = [];
...
LongSword.prototype.addSkill = function skills(skill){
...
Then, you'll be able to add multiple skills :
var Robert = new Player();
Robert.equipWeapon(new LongSword());
Robert.primaryWeapon.addSkill(new Stab());
Robert.primaryWeapon.addSkill(new Stab());
I am working on a small JavaScript application that will users to click on buttons on the page and pass it through to thier basket. The problem I have with doing this is I am unsure as to handle multiple buttons within the same function. I do not want to have to write out different functions for each button.
I am trying to do it OOP and have this so far:
var shop = {};
shop.items = [];
shop.Item = function(item, description, price) {
this.item = item;
this.description = description;
this.price = price;
};
shop.print = function() {
var itemCon = document.getElementById('items'),
html = "";
for(var i = 0; i < this.items.length; i++) {
html += '<div id="item">';
for(prop in this.items[i]) {
html += '<p><span class="title">' + prop + '</span>: ' + this.items[i][prop] + '</p>';
};
html += '<button id="' + this.items[i].item + '">Add to Basket</button>'
html += '</div>';
};
itemCon.innerHTML += html;
};
shop.items[shop.items.length] = new shop.Item("Coat", "Warm", "20");
shop.items[shop.items.length] = new shop.Item("Coat", "Warm", "20");
shop.items[shop.items.length] = new shop.Item("Coat", "Warm", "20");
shop.items[shop.items.length] = new shop.Item("Coat", "Warm", "20");
var basket = {};
basket.items = [];
basket.Item = function(item, description, price) {
this.item = item;
this.description = description;
this.price = price;
};
basket.add = function(data) {
this.items[items.length] = new Item(data.item, data.description, data.price);
};
basket.costCalculate = function() {
var cost = 0,
html = "Total: " + cost;
for(var i = 0; i < this.items.length; i++) {
cost += items[i].price;
};
return html;
};
basket.print = function() {
var output;
for(var i = 0; i < this.items.length; i++) {
for(prop in this.items[i]) {
console.log(prop + ": " + this.items[i][prop]);
};
};
};
function init() {
shop.print()
};
window.onload = init;
How would I determine what item has been clicked in order to run basket.add(data). How would I also pass through the data to that function for each item.
Also how would one go about implementing closure? I understand that it is inner functions having access to the variables of the outer functions, is what I am doing working with closure so far?
Okay, you've made a pretty good start but here are a couple suggestions:
It's probably a good idea to only have one instance of each Item. By that I mean it looks like you create a bunch of Items for to populate your shop's inventory, so for example:
var coat = new Item("Coat", "Warm", 20);
shop.items.push(coat);
Now when you click on your UI element, you ideally want this same instance of coat to go into your basket as well, so:
// User clicks on UI element, which triggers the following to execute:
basket.add( someItemIdentifier );
So now if you ever decide to increase all your prices by $10, you can simply do:
shop.increasePricesBy = function(amount) {
for(var i = 0; i < shop.items.length; i++) {
shop.items[i].price += amount;
}
// execute some function to update existing baskets' totals
};
I hope this makes sense for why there should be one instance of each item that multiple collections refer to.
This begs the question how you can tie the customer's interaction to adding the correct item. One solution could be to use arbitrary IDs to track items. For example:
// Create new item with some randomly generated ID
var coat = new Item({
id: "93523452-34523452",
name: "Coat",
description: "Warm",
price: 20
});
shop.items = {}; // Use a hash so it's easier to find items
shop.items[coat.id] = coat;
And your UI element could be some div like so:
<div class="add-product-button" data-id="93523452-34523452">
Add your click handler:
// Pure JS solution - untested
var clickTargets = document.getElementsByClassName("add-product-button");
for(var i = 0; i < clickTargets.length; i++) {
var clickTarget = clickTargets[i];
clickTarget.onClick = function() {
var itemID = clickTarget.getAttribute("data-id");
var item = shop.items[itemID];
basket.add(item);
};
}
// Equivalent jQuery code
$(".add-product-button").click(function() {
var id = $(this).attr('data-id');
var item = shop.items[id];
basket.add(item);
});
While your basket implements add something like:
basket.add = function(items) {
this.items.push(item);
};
And your costCalculate method gets a whole lot easier:
basket.costCalculate = function() {
var cost = 0;
for(var i = 0; i < this.items.length; i++) {
cost += this.item[i].price;
}
return cost;
};
Instead of doing this:
shop.items[shop.items.length] = new shop.Item("Coat", "Warm", "20");
You can instead do:
shop.items.push(new shop.Item("Coat", "Warm", "20");
Probably a good idea to use a number instead of a string to represent the price.
In your shop.print loop, you probably don't want to hard code <div id="item"> because that will result in multiple divs with the same id.
Finally, I'm not going to try to answer your closure question here because I think that's been answered better than I can already so I'll just link you to some great resources that helped me understand it:
Best stackoverflow thread on how JS Closures work
MDN's doc on closures
Javascript: The Good Parts by Douglas Crockford. It's a tiny book, and talks about some great concepts - especially working with Prototypes which I suspect you'd find useful to help you with this project.
Let me know if you have any questions, I'm totally down to discuss them.
So I have been writing a script to play a video (or really text-based) poker game as an exercise in learning Javascript. I have everything working to play through an instance of the game once, but on trying to run it a second time, it develops an error: "Uncaught TypeError: object is not a function"
This error comes up when trying to create a new hand.
Here is the relevant code, I left a few functions out that don't seem to be causing any issues:
//object constructor for card
function card(suite, faceValue) {
this.suite = suite,
this.faceValue = faceValue
}
//object constructor for hand
function hand(cards, handName, score, docHandName) {
this.cards = cards,
this.handName = handName,
this.score = score,
this.docHandName = docHandName
}
var deck = new Array;
var buildDeck = function() {
for (var i = 0; i <= 52; i++) {
if (i < 13) {
deck[i] = new card("Spades", i + 2);
}
else if (i < 26) {
deck[i] = new card("Clubs", i - 11);
}
else if (i < 39) {
deck[i] = new card("Hearts", i - 24);
}
else if (i < 52) {
deck[i] = new card("Diamonds", i - 37);
}
}
}
//pulls a card from location in deck specified by randomSpot()
var pullCard = function(spot) {
var newCard = deck[spot];
deck.splice(spot, 1);
return newCard;
}
//takes away a card each time
//passes into pullCard(spot) as spot
var pullCount = 0;
var randomSpot = function() {
var x = Math.floor(Math.random() * (52 - pullCount));
pullCount++;
return x;
}
var dealFiveCards = function() {
var card1 = pullCard(randomSpot());
var card2 = pullCard(randomSpot());
var card3 = pullCard(randomSpot());
var card4 = pullCard(randomSpot());
var card5 = pullCard(randomSpot());
var fiveCards = [card1, card2, card3, card4, card5];
return fiveCards;
}
function createNewHand() {
newHand = new hand();
newHand.cards = dealFiveCards();
return newHand;
}
var playOneGame = function() {
buildDeck();
hand = createNewHand();
hand.cards.sort(compare);
assignHandScore();
wager = prompt("How much do you bet?");
printHandValue();
dealAgain();
hand.cards.sort(compare);
assignHandScore();
payout = pays(wager);
printHandValue();
printPayout();
}
playAgain = "Y";
while (playAgain === "Y") {
playOneGame();
playAgain = prompt("Would you like to play again? Y/N").toUpperCase();
}
So the error occurs when trying to run the playOneGame() function a second time. The first time runs fine and a hand is created. The second time when it gets to hand = createNewHand(); it gives the object is not a function error.
To be clear, I have the hand created as an object, which contains properties cards, handName, score, docHandName where cards is an array of card objects, themselves containing properties of suite, faceValue.
The error gives the line newHand = new hand(); in function createNewHand() as the reference line.
Help?
The second line of playOneGame is overriding your global hand function with an instance of hand. So when createNewHand runs again hand it is no longer the same thing.
You should probably rename the function hand to Hand.
I am trying to write my javascript code using modular pattern, but i am facing problem while calling the functions inside and also there are some security problems. I can easily open the console and type in my namespace name . variable and change the variable value.
JS
Below JS Code is working fine, but as i said i can change the gridValue from console. How do i avoid this. i will be using this variable across all my functions.
var myTicTacToe = {
turn:'X',
score: {
'X': 0,
'O': 0
},
gridValue: 0,
fnLoad:function () {
var select = document.getElementById("grid");
for (i = 3; i <= 100; i += 1) {
var option = document.createElement('option');
select.options[select.options.length] = new Option(i + ' X ' + i, i);
}
}
}
window.onload = function(){
myTicTacToe.fnLoad();
}
Below one is giving me problem while calling the fnLoad.
var myTicTacToe = function(){
var turn = 'X',
score = {
'X': 0,
'O': 0
},
gridValue = 0,
fnLoad = function () {
var select = document.getElementById("grid");
for (i = 3; i <= 100; i += 1) {
var option = document.createElement('option');
select.options[select.options.length] = new Option(i + ' X ' + i, i);
}
}
}
window.onload = function(){
myTicTacToe.fnLoad();
}
How can i protect my gridValue or any of the variable in First pattern ?
Why i am not able to call fnLoad just like first one ? how do i call it ?
Whats the difference between these 2 patterns ?
In the first code when i declared any variable using var, it gave me error. Why is it so ?
What you are referring to is the Revealing Module Pattern. Everything is private unless you explicitly return it
var myTicTacToe = (function(){
var turn = 'X',
score = {
'X': 0,
'O': 0
},
gridValue = 0,
fnLoad = function () {
var select = document.getElementById("grid");
for (i = 3; i <= 100; i += 1) {
var option = document.createElement('option');
select.options[select.options.length] = new Option(i + ' X ' + i, i);
}
};
return {
load: fnLoad //fnLoad is now publicly named "load".
};
})();
window.onload = function(){
myTicTacToe.load();
}
/* Or even
window.onload = myTicTacToe.load; //Because it's a single function.
*/
As for your concrete questions:
You can't. All object members are public by default with the normal Module Pattern.
Because you haven't returned it, see the example above.
One allows for private members, and one does not. The revealing pattern allows for privates.
I didn't understand which variable we are talking about. But if it's an object member, it should not be declared with a var.
You can use a closure to make gridValue a private variable. Consider this pattern:
var myTicTacToe = (function(){
var turn = 'X'.
score = {
'X': 0,
'O': 0
},
gridValue = 0;
return {
fnLoad: function () {
var select = document.getElementById("grid");
for (i = 3; i <= 100; i += 1) {
var option = document.createElement('option');
select.options[select.options.length] = new Option(i + ' X ' + i, i);
}
}
};
})();
window.onload = function(){
myTicTacToe.fnLoad();
}
Here we use an IIFE to close in the local variables so that only the fnLoad function has access to them. Later the fnLoad function is returned and invoked fill the namespace so it can be public ally accessed by other parts of your program.
This pattern can be extremely useful. Read more here: http://css-tricks.com/how-do-you-structure-javascript-the-module-pattern-edition/
This links is my constant reference when working with javascript. It does an amazing job of explaining the different patterns to use with javascript and I bet will help solve your issue.
http://www.addyosmani.com/resources/essentialjsdesignpatterns/book/#designpatternsjavascript
Here is your code refactored to protect your private variables and only allow methods to be public that you declare. I am using the "Revealing Modular Pattern" below.
var myTicTacToe = (function () {
// PRIVATE AREA
var turn = 'X';
var score = {
'X': 0,
'O': 0
};
var gridValue = 0;
function fnLoad() {
var select = document.getElementById("grid");
for (i = 3; i <= 100; i += 1) {
var option = document.createElement('option');
select.options[select.options.length] = new Option(i + ' X ' + i, i);
}
}
// PUBLIC METHODS
return {
Load: fnLoad
}
})();
then call it like
myTicTacToe.Load();
If you need to pass a dependency in such as jQuery or another module you've created then you would create the parameter in the (function(HERE) and then pass it in at the bottom in the last set of parentheses. Here is an example of your code with jQuery.
var myTicTacToe = (function ($) {
// PRIVATE AREA
var turn = 'X';
var score = {
'X': 0,
'O': 0
};
var gridValue = 0;
function fnLoad() {
var select = $('#grid');
for (i = 3; i <= 100; i += 1) {
var option = document.createElement('option');
select.options[select.options.length] = new Option(i + ' X ' + i, i);
}
}
// PUBLIC METHODS
return {
Load: fnLoad
}
})($);
I am doing a website wich has a lot of animations managed by JavaScript, when i started i just defined a function and some variables for the animation and repeat the process, like this. And a think is not the good way.
//BRIGHT ANIMATION
var frameWidth1 = 386;
var frameHeight1 = 100;
var spriteWidth1 = 20067;
var spriteHeight1 = 100;
var spriteElement1 = document.getElementById("bright");
var curPx1 = 0;
var ti1;
function animateSpriteB() {
spriteElement1.style.backgroundPosition = "-" + curPx1 + 'px 0px';
curPx1 = curPx1 + frameWidth1;
if (curPx1 >= spriteWidth1) {
curPx1 = 0;
}
ti1 = setTimeout(animateSpriteB, 70);
}
animateSpriteB();
// PAPIRO ANIMATION
var frameWidth = 56;
var frameHeight = 218;
var spriteWidth = 2016;
var spriteHeight = 218;
var spriteElement = document.getElementById("roll-off");
var curPx = 0;
var ti;
function animateSprite() {
spriteElement.style.backgroundPosition = "-" + curPx + 'px 0px';
curPx = curPx + frameWidth;
ti = setTimeout(animateSprite, 27.7);
if (curPx === spriteWidth) {
clearTimeout(ti);
}
}
function slideMask(){
var mask = $("#paper-mask");
var paper = $("#paper");
mask.animate({
width: 450
},{
duration: 1000,
complete: function(){
$("#paper-content").fadeIn();
}
});
}
var ti = setTimeout(function(){
animateSprite();
slideMask();
}, 3000);
So know, I decided to use a constructor to re use the same code and manage all the animations in the website. i came with Something like this:
// CONSTRUCTOR WHO MANAGE THE ANIMATIONS FOR THE WEBSITE
function SpriteAnimation(frameWidth, spriteWidth, spriteElement, isLoop){
this.frameWidth = frameWidth;
this.spriteWidth = spriteWidth;
this.spriteElement = spriteElement;
this.isLoop = isLoop;
this.curPx = 0;
this.ti;
}
SpriteAnimation.prototype.start = function(){
var selector = document.getElementById(this.spriteElement);
selector.style.backgroundPosition = "-" + this.curPx + "px 0px";
this.curPx = this.curPx + this.frameWidth;
this.ti = setTimeout(this.start, 2000);
if (this.curPx === this.spriteWidth){
clearTimeout(this.ti);
}
this.start();
}
var letter = new SpriteAnimation(935.4, 17774, "letter", true);
letter.start();
I am having problems in performance, every time i run the code my browser just crash i also think im not doing good the loop. So here comes my question: how can i do to manage the animations with an object constructor in wich i can pass parameters like if it is loop animation and the sprite parameters?... I appreciate the help you guys can bring me :)
#Tibos Your code has been from great help for me i just spent almost 4 hours trying to achieve this, and then yo came out and make it really easy, this is how my code looks now, i added another parameter: frame rate. so every animation can have a different frame rate. Also modified a bit the if statement because the animation was running untill the sprite dissapear and i need them to stay in the last frame, let me know if this is the correct form.
// CONSTRUCTOR WHO MANAGE THE ANIMATIONS FOR THE WEBSITE
function SpriteAnimation(frameWidth, spriteWidth, spriteElement, shouldLoop, frameRate){
this.frameWidth = frameWidth;
this.spriteWidth = spriteWidth;
this.selector = document.getElementById(spriteElement);
this.shouldLoop = shouldLoop ;
this.curPx = 0;
this.frameRate = frameRate;
this.ti;
}
SpriteAnimation.prototype.start = function(){
this.selector.style.backgroundPosition = "-" + this.curPx + "px 0px";
this.curPx += this.frameWidth;
if (this.curPx < (this.spriteWidth - this.frameWidth)){
setTimeout(this.start.bind(this), this.frameRate);
} else if (this.shouldLoop) {
this.curPx = 0;
this.start();
}
};
var letter = new SpriteAnimation(935.4, 17774, "letter", true, 60);
letter.start();
You have a few problems in your code, presented here in order of impact:
recursively calling start
losing the reference to this
clearing timeout as soon as it's set
unused variables
selecting the element at each iteration
Here is some better code (that works):
function SpriteAnimation(frameWidth, spriteWidth, spriteElement, shouldLoop){
this.frameWidth = frameWidth;
this.spriteWidth = spriteWidth;
this.selector = document.getElementById(spriteElement);
this.curPx = 0;
this.shouldLoop = shouldLoop;
}
SpriteAnimation.prototype.start = function(){
this.selector.style.backgroundPosition = "-" + this.curPx + "px 0px";
this.curPx += this.frameWidth;
if (this.curPx <= this.spriteWidth){
setTimeout(this.start.bind(this), 2000);
} else if (this.shouldLoop) {
this.curPx = 0;
this.start();
}
};
var letter = new SpriteAnimation(935.4, 17774, "letter", true);
letter.start();
DEMO: http://jsbin.com/oJIYoRU/1/edit
This function calls itself recursively with no base case. As soon as you invoke it you will lock the UI and overflow the call-stack.
SpriteAnimation.prototype.start = function(){
... some code ...
this.start();
}