I have an object that looks like:
var monsters = {
zombies: {
name: "zombie",
hitPoints: 10,
loot: "magic knife"
},
skeleton: {
name: "skeleton",
hitPoints: 15,
loot: "magic shield"
},
ghoul: {
name: "ghoul",
hitPoints: 12,
loot: "magic helm"
}
};
I'm trying to set a function that will randomly select one of the properties in the variable. (zombies, skeleton, ghoul)
Here's what I have:
var travel = function(direction) {
var newRoom = rooms[currentRoom.paths[direction]];
if (!newRoom) {
$("<p>You can't go that way.</p>").properDisplay();
}
else {
currentRoom = newRoom;
$("<p>You are now in the " + currentRoom.name + " Room.</p>").properDisplay();
if (currentRoom.hasMonsters) {
function pickRand(monsters) {
var result;
var count = 0;
for (var prop in monsters)
if (Math.random() < 1/++count)
result = prop;
return $("<p>Holy Crap! There's a" + result + "in here!</p>").properDisplay();
}
}
else {
$("<p>Whew! Nothing here.</p>").properDisplay();
}
}
};
Note: The hasMonsters is in a separate object. It determines if a specific room has a monster or not.
How can I randomly select one of the monsters and insert in the output? I'm guessing I'm calling the object incorrectly and that's why it's not working.
Will something like this work? You can keep your monsters as an object and use Object.keys to fetch your keys (in this case your monsters) as an array. Then it's just a matter of plucking out a random monster with Math.random:
// so you have some object where the keys are your monsters
var monsters = { ghost: '..', skeleton: '..', donald_trump: '..'};
// grab your monsters above as an array
var monsterArray = Object.keys(monsters);
// pick your monster at random
var randomKey = Math.floor(Math.random() * monsterArray.length);
console.log('holy crap we found a ' + monsterArray[randomKey]);
now I see what you're asking. I want the name property called. Right
now it will properly call what I'm guessing is the entire object. How
do i call the name only?
Try using Object.keys()
var monsters = {
zombies: {
name: "zombie",
hitPoints: 10,
loot: "magic knife"
},
skeleton: {
name: "skeleton",
hitPoints: 15,
loot: "magic shield"
},
ghoul: {
name: "ghoul",
hitPoints: 12,
loot: "magic helm"
}
};
document.body.onclick = function() {
var keys = Object.keys(monsters);
var rand = Math.floor(Math.random() * keys.length)
var res = monsters[keys[rand]];
var key = Object.keys(res);
var prop = res[key[Math.floor(Math.random() * key.length)]];
console.log(res, prop);
this.innerHTML += "<br>" + JSON.stringify(prop) + "<br>"
}
click
Related
I have a data structure like this
{
"stores": [
{ code: 'A7-22', name: 'market'},
{ code: 'A8-22', name: 'drugstore'},
... 250 items
]
}
Then in the code I search a store using:
const code = 'A7-22';
const store = data.stores.find(store => store.code === code)
But I think that could be a good idea to change the data structure to
{
"stores": {
'A7-22': {name: 'market'},
'A8-22': { name: 'drugstore'},
... 250 items
]
}
and now the code it is more easy to handle:
const code = 'A7-22';
const store = data.stores[code]
Now, consider that this code is running in a backend artifact with high traffic and in the future, the store could be > 10.000.
The question is:
There are some performance issues related to this code if I take the option 2 using a large object with "key value strategy"?
Yes, absolutely the second option is faster. Here is the challenge for two cases:
var code = 'A7-22', store={};
var data = {
"stores": [
{ code: 'A8-22', name: 'drugstore'},
]
};
for(var i=1; i<10000; i++) {
data.stores.push({ code: 'x'+i, name: 'v'+i});
}
data.stores.push({ code: 'A7-22', name: 'market'});
var t1 = new Date();
for(var i=1; i<1000; i++) {
store = data.stores.find(store => store.code === code);
}
var t2 = new Date();
var dt = (t2.getTime() - t1.getTime());
document.write("<p> <b>Option 1 (using find):</b> " + code + ": " + store.name + ', dt: '+ dt + " msec</p>");
// -------------------
var data2 = {
"stores": {
'A8-22': {name: 'drugstore'}
}
};
for(var i=1; i<10000; i++) {
data2.stores['x'+i] = {name: 'v'+i};
}
data2.stores['A7-22'] = { name: 'market'};
var t1 = new Date();
for(var i=1; i<1000; i++) {
store = data2.stores[code]
}
var t2 = new Date();
var dt = (t2.getTime() - t1.getTime());
document.write("<p> <b>Option 2 (using array index):</b> " + code + ": " + store.name + ', dt: '+ dt + "msec</p>");
Note that the high traffic you mentioned is not important here as this code is run in clients.
I have the following JavaScript code:
function Product(){
this.ProductName="";
this.Quantity=0;
this.Price=0;
this.Category="";
this.Total=function() {
return this.Quantity * this.Price;
}
this.Discount=function() {
return this.Total() * 0.25;
}
}
var Product = new Product();
Product.ProductName="Tipkovnica";
Product.Quantity=100;
Product.Price=150.5;
Product.Category="IT";
if(localStorage.Products){
Products = JSON.parse(localStorage.getItem("Products"));
}
else
{
var Products = [];
}
Products.push(Product);
localStorage.setItem('Products', JSON.stringify(Products));
function RetrieveObjects(Products){
for(var a=0;a<Products.length; a++){
document.write("<br>Product Name: "+Products[a].ProductName);
document.write("<br>Quantity: "+Products[a].Quantity);
document.write("<br>Price: "+Products[a].Price);
document.write("<br>Category: "+Products[a].Category);
document.write("<br>Total: "+Products[a].Total());
document.write("<br>Discount: "+Products[a].Discount());
}
}
I made JSON.stringify to store array object in JSON.
Then, When I tried to loop object from array back from storage after JSON parse, I got error because methods Total() and Discount() were not recognized as methods.
Any idea why?
Thanks,
Milan
Your function is using this but that is the global this which is the window object.
However, there is another problem, you cannot (or rather should not) store functions in JSON as there is no function data type. You should calculate the values and store the result in your JSON.
var Product {
productName: null,
quantity: 0,
price: 0,
category: null,
finalTotal: 0,
discountedTotal: 0,
total: function() {
return this.quantity * this.price;
},
discount: function() {
return this.total() * 0.25;
}
}
var newProduct = Object.create(Product);
newProduct.productName = "Tipkovnica";
newProduct.quantity = 100;
newProduct.price = 150.5;
newProduct.category = "IT";
newProduct.finalTotal = newProduct.total();
newProduct.discountedTotal = newProduct.discount();
if (localStorage.Products) {
Products = JSON.parse(localStorage.getItem("Products"));
Products.push(newProduct);
} else {
Products = [newProduct];
}
localStorage.setItem('Products', JSON.stringify(Products));
function RetrieveObjects(Products) {
for (var a = 0; a < Products.length; a++) {
document.write("<br>Product Name: " + Products[a].productName);
document.write("<br>Quantity: " + Products[a].quantity);
document.write("<br>Price: " + Products[a].price);
document.write("<br>Category: " + Products[a].category);
document.write("<br>Total: " + Products[a].finalTotal);
document.write("<br>Discount: " + Products[a].discountedTotal);
}
}
Because if you stringify the object, then all the methods are removed. Take a look at this: https://stackblitz.com/edit/typescript-2tfnkr
Not related hint: use the camelCase instead of PascalCase convention for all of the methods, properties and variables. PascalCase should be used in class names, interfaces etc.
I currently have a solution using AngularJS/SpreadJS where we need to update the header section with a formula. When we change a cell value in the header using setValue everythign displays ok, however we need to display a formula using setFormula, in these cases the formula gets calculated and displayed in the rows belonging to the actual sheet where my data is at.
//Does not work and displays in row 2 of the sheet:
sheet.setFormula(2, i, formula, GC.Spread.Sheets.SheetArea.colHeader);
//Displays value in actual header in teh correct location/header cell
sheet.setValue(2, i, 'my formula!', GC.Spread.Sheets.SheetArea.colHeader);
Any help will be appreciated. Thanks!
Implemented below solution to achieve the SUM formula in Column Header of the spread sheet.This function can be called on spread sheet events like cellChanged,clipBoardPasted to achieve functionality.
var spread = new GC.Spread.Sheets.Workbook($("#ss").get(0), { sheetCount: 2 });
var displaySheet = spread.getSheet(0);
displaySheet.setRowCount(2, GC.Spread.Sheets.SheetArea.colHeader);
for (var i = 0; i < 10; i++) {
for (var j = 0; j < 10; j++) {
displaySheet.setValue(i, j, i + j);
}
}
$("#btnSetAutoTotal").click(function () {
setTotal(displaySheet, 0);
});
function setTotal(sheet, columnIndex) {
var formula = "SUM(R[1]C[1]:R[10]C[10]";
value = GC.Spread.Sheets.CalcEngine.evaluateFormula(sheet, 'SUM(A:A)', 0,
columnIndex, false);
sheet.setValue(0, columnIndex, value, GC.Spread.Sheets.SheetArea.colHeader);
};
The team created this sample to demonstrate what you need. Hope this helps.
function setColumnHeaderFunction() {
this.name = "SetColumnHeader";
this.maxArgs = 3;
this.minArgs = 3;
}
setColumnHeaderFunction.prototype = new GC.Spread.CalcEngine.Functions.Function();
setColumnHeaderFunction.prototype.description = function () {
return {
name:"SetColumnHeader",
description: "The function will apply the calc result on specified column",
parameters: [{
name: "result",
description: "The value which will be setted on column"
}, {
name: "rowIndex",
description: "The row index"
}, {
name: "colIndex",
description: "The column index"
}]
}
}
setColumnHeaderFunction.prototype.evaluate = function () {
var value = arguments[0], rowIndex = arguments[1], colIndex = arguments[2];
var spread = GC.Spread.Sheets.findControl("ss");
var sheet = spread.getSheet(0);
sheet.setValue(rowIndex, colIndex, value, GC.Spread.Sheets.SheetArea.colHeader);
}
$(document).ready(function () {
var spread = new GC.Spread.Sheets.Workbook($("#ss").get(0), {sheetCount: 2});
spread.addCustomFunction(new setColumnHeaderFunction());
var displaySheet = spread.getSheet(0);
displaySheet.setDataSource(getSource(100));
displaySheet.setRowCount(3, GC.Spread.Sheets.SheetArea.colHeader);
displaySheet.setValue(0,0,"Count:",GC.Spread.Sheets.SheetArea.colHeader);
displaySheet.setValue(0,3,"Sum:",GC.Spread.Sheets.SheetArea.colHeader);
displaySheet.setValue(0,4,"Average:",GC.Spread.Sheets.SheetArea.colHeader);
displaySheet.setValue(0,5,"Sum:",GC.Spread.Sheets.SheetArea.colHeader);
var calcSheet = spread.getSheet(1);
calcSheet.visible(false);
calcSheet.setFormula(0, 1, "SetColumnHeader(SUM(Sheet1!D:D),1,3)");
calcSheet.setFormula(0, 2, "SetColumnHeader(AVERAGE(Sheet1!E:E),1,4)");
calcSheet.setFormula(0, 3, "SetColumnHeader(SUM(Sheet1!F:F),1,5)");
calcSheet.setFormula(0, 4, "SetColumnHeader(COUNT(Sheet1!A:A),1,0)");
});
function getSource(count) {
var dataList = [];
var _lines = ["Computers", "Washers", "Stoves"];
var _colors = ["Red", "Green", "Blue", "White"];
for (var i = 0; i < count; i++) {
dataList.push({
id: i,
line: _lines[parseInt(Math.random() * 3)],
color: _colors[parseInt(Math.random() * 4)],
price: parseInt(Math.random() * 501 + 500),
cost: parseInt(Math.random() * 601),
weight: parseInt(Math.random() * 101),
})
}
return dataList;
}
To keep it short and let the example speak for itself.
I create a object and print it out (it's OK), I create more objects (of the same type) and print out the first object again, now it shows the data of the last object created.
Then I create a a different object from a different class and print the original first object out again and it returns the data from the newly created object.
JSFiddle
var uiElements = [];
uiElements.borders = [];
uiElements.buttons = [];
uiElements.text = [];
var mainStats = [];
mainStats.money = 0;
mainStats.pots = [];
mainStats.herbs = [];
var xOffSet = 10;
var yOffSet = 10;
$(document).ready(function() {
createUI();
});
function createUI()
{
mainStats.herbs.types = [];
mainStats.herbs.types[0] = "Blue";
mainStats.herbs.types[1] = "Blood vine";
mainStats.herbs.types[2] = "Heg flower";
mainStats.herbs[mainStats.herbs.types[0]] = createHerb(mainStats.herbs.types[0], "herb", 60, 0.2, 10, "Basic blue herb", 1, true);
//CORRECT
alert(mainStats.herbs[mainStats.herbs.types[0]].name +" "+ mainStats.herbs[mainStats.herbs.types[0]].tier)
mainStats.herbs[mainStats.herbs.types[1]] = createHerb(mainStats.herbs.types[1], "herb", 200, 0.4, 40, "Blood red tree vine", 1, true);
mainStats.herbs[mainStats.herbs.types[2]] = createHerb(mainStats.herbs.types[2], "herb", 390.4, 0.2, 202.5, "Crescent shape flower", 1, true);
mainStats.herbs.types[3] = "Black rose";
mainStats.herbs[mainStats.herbs.types[3]] = createHerb(mainStats.herbs.types[3], "herb", 60, 0.2, 10, "Very dark rose", 2, true);
mainStats.pots.types = [];
mainStats.pots.types[0] = "Earthen";
//mainStats.pots[mainStats.pots.types[0]] = [];
//mainStats.pots[mainStats.pots.types[0]].color = "#654321";
//WRONG
alert(mainStats.herbs[mainStats.herbs.types[0]].name +" "+ mainStats.herbs[mainStats.herbs.types[0]].tier)
createPot(mainStats.pots.types[0], 1, 1, null);
//VERY WRONG
alert(mainStats.herbs[mainStats.herbs.types[0]].name +" "+ mainStats.herbs[mainStats.herbs.types[0]].tier)
}
function createPot(name, tier, growthAccelerator, herb)
{
this.name = name;
this.tier = tier;
this.growthAccelerator = growthAccelerator;
this.herb = herb;
this.timeLeft = 0;
return this;
}
function createHerb(name, type, timeToBloom, seedsReturned, salesPrice, description, tier, enabled)
{
this.name = name;
this.type = type;
this.timeToBloom = timeToBloom;
this.seedsReturned = seedsReturned;
this.salesPrice = salesPrice;
this.description = description;
this.tier = tier;
this.enabled = enabled;
return this;
}
function rx(num)
{
return num+xOffSet;
}
function ry(num)
{
return num+xOffSet;
}
You don't create objects but just call the functions so their this refers to the global (window) object so that the properties there are overwritten each time and you print out the modified stuff
Create objects with the new keyword like this (by convention, you would then rename createPot just Pot)
var newObj = new createPot(mainStats.pots.types[0], 1, 1, null);
alert(newObj.name);
...
function Money(bill, accu, hb, food, webHosting, lynda) {
Money.bill = bill;
Money.accu = accu;
Money.hb = hb;
Money.food = food;
Money.webHosting = webHosting;
Money.lynda = lynda;
Money.total = function () {
(Money.bill + Money.accu + Money.hb + Money.food + Money.webHosting + Money.lynda)
return Money.total;
};
}
var cost = new Money(2500, 5000, 2000, 6000, 1000, 30000);
Money.total();
I have defined everything for a object using a variable at the end.
When I run Money.total(the "money" objects method) it returns as ""function""
Please help.I want the total of everything.
You need to use this instead of `Money' to read/write properties of the newly created object:
function Money(bill, accu, hb, food, webHosting, lynda) {
this.bill = bill;
this.accu = accu;
this.hb = hb;
this.food = food;
this.webHosting = webHosting;
this.lynda = lynda;
this.total = function() {
return this.bill + this.accu + this.hb + this.food + this.webHosting + this.lynda;
}
}
It's unclear what you were trying to do with your 'total' method. If you can describe what that is supposed to do, then we could help with that implementation, but I've provided an implementation that sums the properties.