What's the easiest way to store and load data Javascript? - javascript

I have a Hashmap for storing Loudness values. The code is in Javascript HTML5.
var Loudness = {};
Loudness['f125'] = {right: [], left: []};
Loudness['f125']['right'].push([0,10,30, 40]);
Loudness['f125']['left'].push([5,15,35,45]);
Loudness['f250'] = {right: [], left:[] };
Loudness['f500'] = {right: [], left: []};
Loudness['f1000'] = {right: [], left: []};
I also have a Hashmap for storing Gain values (basically the same as up, also w/ "right" and "left" (right and left side of the audiospeakers) properties.
The difference is the name of the HM and the values of the array. I have a lot of frequencies (keys, for instance f250, f500, …) still to insert to each Hashmap. Is there a more efficient way to declare each frequency key and its properties?
Does it make sense to use a Hashmap inside a Hashmap?
Also, if the Gain HM is put inside the Loudness HM, how would the new Loudness HM disposition be like? Do the keys(frequencies) remain the same? Is the GainHashmap now a new property?
I haven’t found how to implement it. What would the syntax be like?
What's the easiest way to insert and easily change data ("loudness" and "gain" for "right" and "left", for each frequency).
Is there a better option in your opinion? WebStorageAPI, Hashmap inside Hashmap?
Please consider that I'm not such an expert in programming. Any help is greatly Appreciated.

var Loudness = {};
var freqs = ['f125', 'f250', 'f500', 'f1000', 'f1250'];
var values = [0, 10, 30, 40, 5, 15, 35, 45];
for(var i in freqs){
Loudness[freqs[i]] = {left : [], right : []};
Loudness[freqs[i]].Gain = {left : [], right : []};
for(var j in values){
var v = values[j];
if(v === 0 || v % 2 === 0){
Loudness[freqs[i]]['right'].push(v);
Loudness[freqs[i]].Gain['right'].push(v);
} else {
Loudness[freqs[i]]['left'].push(v);
Loudness[freqs[i]].Gain['left'].push(v);
}
}
}
Try this one. In order to access your gains:
Loudness['f125'].Gain.left[0]
Basically if you need more frequencies, just add them to freqs arrays.

So, the idea of Gain as property inside the Loudness HM is perfect.
The problem is that this Loudness HM is not allowed to be accessed (wherever and however it was declared).
1) I tried to make it acessible even through privileged methods returning it.
2) I even declared it inside a constructor (using this.Loudness = {}; instead of var Loudness = {};, but am receiving errors like "Uncaught TypeError: Cannot read property '250' of undefined", when trying to access this value. Piece of the public method which uses it:
AudiometrySample.prototype.loudnessToGain = function (frequency, loudness, activeChannel) {
...
console.log("this.Loudness[250] is"+ this.Loudness);
if (this.activeChannel === "right") {
for (var j = 0; j < this.Loudness[this.frequency].right.length; j++) {
if (this.Loudness[this.frequency].right[j] === this.loudness) {
this.wantedGain = this.Loudness[this.frequency].Gain.right[j];
this.currentPairIndex = j;
}
}
}
This console log gives "undefined" back. How to make it accessible?

Related

Are there cases in which Array.isArray() doesn't work?

So I've been trying to debug a physics engine I'm writing, and for a multi-dimensional spatial hashmap I'm needing to allocate a 2D array of arrays.
Why does this code give me "Cannot read property 'push' of undefined"? Is there something happening in the line between my if statements and my trying to push on to the array?
EDIT "this" refers to a PhysicsEngine instance, it keeps a reference to the "entities" array as well as a "hashmap" array.
function PhysicsEngine(game) {
this.game = game;
this.entities = [];
this.hashmap = createArray(32, 32);
}
for(var i = 0; i < this.entities.length; i++) {
//Array item may not be a Simulateable Entity
//this.entities[i].simulatePhysics(this);
this.entities[i].ResolveCollisions();
this.entities[i].Move();
hmx = Math.round(Math.abs(this.entities[i].x/32));
hmy = Math.round(Math.abs(this.entities[i].y/32));
if(!logged) {
console.log(this.hashmap);
console.log(this.entities[i]);
console.log(i, hmx, hmy);
console.log(this.hashmap[hmx], this.hashmap[hmy]);
logged = true;
}
if(!Array.isArray(this.hashmap[hmx])) {
this.hashmap[hmx] = [];
if(!Array.isArray(this.hashmap[hmx][hmy])) {
this.hashmap[hmx][hmy] = [];
}
}
this.hashmap[hmx][hmy].push(this.entities[i]);
}
I think that this code:
this.hashmap[hmx] = [];
if(!Array.isArray(this.hashmap[hmx][hmy])) {
this.hashmap[hmx][hmy] = [];
}
is not correct. In particular, the "if" condition tests whether this.hashmap[hmx][hmy] is an array. The problem is that this.hashmap[hmx]=[] (as you have set one line before), so this.hashmap[hmx][hmy] is undefined and javascript throws an error "Undefined is not an object".
Maybe is this the problem?

Handle undefined as an object

Is there a technique / framework, which creates and stores a new object into an undefined variable when it is handled as an object?
F.e. writing
some.thing = 7;
Gives an error describing, that undefined's ( some's ) property could not be set.
So now, we have to go back, and write
some = {};
some.thing = 7;
which looks almost unnecessary to me, since it is obvious, that I'd like to use some as an object.
It would be very comfortable this way:
hospitals.sectors.doctors = [];
hospitals.sectors.doctors[ 0 ].age = 32;
This looks way more efficient, and simple than
hospitals = {};
hospitals.sectors = {};
hospitals.sectors.doctors = [];
hospitals.sectors.doctors[ 0 ] = {};
hospitals.sectors.doctors[ 0 ].age = 32;
If you are trying to assign 7 to some.thing and some should not be declared at all beforehand, use Cory's suggestion of var some = { thing: 7 };.
If you are trying to assign 7 to some.thing and some might be declared/defined already (or even if it is declared, may or may not be set to undefined), use
(some = (some || {})).thing = 7;
or (a more readable solution, though not a one liner)
some = (some || {});
some.thing = 7;
The one caveat with my solution is that you might get undesired scoping on some if it isn't declared ahead of time. An example of where it would be undefined but still declared (and thus the scope would be what is expected):
function assignThing(some) {
(some = (some || {})).thing = 7; /* one liner solution */
return some;
}
var foo = assignThing(); /* the parameter 'some' is undefined, but declared */
var bar = assignThing({}); /* the parameter 'some' is defined
* (though empty) and declared */
(baz = (baz || {})).thing = 7; /* Unless you have this declared
* elsewhere this *should* be the
* global scope */
var foobar; /* declared, not defined */
(foobar = (foobar || {})).thing = 7; /* now defined */
Edit: Created a namespace solution like what anddoutoi suggested.
First example of usage (hospitals) uses the optional nature of the third parameter, which defaults to "undefined".
Second example (hospitals2) passes undefined.
Third example (hospitals3) passes another object (I happened to create it inline).
For the example you (the OP) provided, my hospitals example is the closest to an exact match. I don't know of a way to auto-magically create an object hierarchy besides using a canonical name string + a function.
function create(canonicalPropertyName, value, root) {
root = (root || {});
var names = canonicalPropertyName.split(".");
var current = root;
for (var i = 0; i < names.length; i++) {
/* Ensure the property exists */
current[names[i]] = (current[names[i]] || (i < names.length - 1 ? {} : []));
/* We're recursing down the object tree */
current = current[names[i]];
}
return root;
}
var hospitals = create("sectors.doctors", []);
hospitals.sectors.doctors[ 0 ] = {};
hospitals.sectors.doctors[ 0 ].age = 32;
console.log(hospitals);
var hospitals2 = create("sectors.doctors", [], undefined);
hospitals2.sectors.doctors[ 0 ] = {};
hospitals2.sectors.doctors[ 0 ].age = 32;
console.log(hospitals2);
var hospitals3 = create("sectors.doctors", [], { name: "City Hospital" });
hospitals3.sectors.doctors[ 0 ] = {};
hospitals3.sectors.doctors[ 0 ].age = 32;
console.log(hospitals3);
Many frameworks have a namespace() method/function that helps you achieve what you want.
http://yuilibrary.com/yui/docs/api/classes/YUI.html#method_namespace
https://docs.sencha.com/extjs/5.1/5.1.1-apidocs/#!/api/Ext-method-namespace
Example:
Ext.ns('hospitals.sectors.doctors') = [];
var doctors = Ext.ns('hospitals.sectors.doctors');
doctors[0] = {
age : 32
};
I myself don't like this pattern as it adds unnecessary dependencies and work.
you could write an own handler to do the job
function createObjectProperty(objNameString, objPropertyString, objValueString) {
window[objNameString] = {};
window[objNameString][objPropertyString] = objValueString;
return window[objNameString];}
var test = createObjectProperty("some", "thing", 7);
alert(test.thing);
the call would look like:
createObjectProperty("some", "thing", 7);
and it alerts "7".You also could check before creating the new object, if it exists. I would iterate over the object and gather all attributes, check for duplicate and append my new attribute + value if you need such functionality. Otherwise the new object will overwrite the old one. Hope this is what you are searching for
working fiddle (update):
https://jsfiddle.net/a922bopj/1/

Optimizing Nested For Loop

I'm working on a performance-intensive library and wanted to see if anyone had some ideas on how to improve the performance of this method which converts our models to a js object.
You'll see below that I've tried to employ a couple of optimization techniques based on my reading:
Use straight for loops to iterate objects, arrays
Cache nested objects to avoid excessive lookups (field = fields[i], etc).
Here's the method I'm trying to further optimize:
toObject: function() {
var i, l, fields, field, schema, obj = {};
for(i = 0, fields = Object.keys(this._schema), l = fields.length; i < l; i++) {
field = fields[i], schema = this._schema[field];
if(!this._data.hasOwnProperty(field) || (schema.hasOwnProperty('output') && !schema[field].output)) {
continue;
}
if(schema.hasOwnProperty('collection')) {
obj[field] = [];
schema.collection.instances.forEach(function (mdl) {
obj[field].push(mdl.toObject());
});
}
obj[field] = schema.hasOwnProperty('processOut') ? schema.processOut.call(this, this._data[field]) : this._data[field];
}
return obj;
}
In particular, I'm wondering if there's a way to optimize:
schema.collection.instances.forEach(function (mdl) {
obj[field].push(mdl.toObject());
});
If I'm not mistaken, the function within the forEach is being created on each iteration. I was going to try and move it out of the main for loop, but then I lose access to field which I need to set the property key on obj.
I also thought about turning this into another for/loop, but then I'd have to create another set of variables like so:
// these vars would be init'd at the top of toObject or
// maybe it makes sense to put them within the parent
// for loop to avoid the additional scope lookup?
var x, xl;
for(x = 0, xl = schema.collection.instances.length; x < xl; x++) {
obj[field].push(schema.collection.instances[x].toObject());
}
This just looks a little ugly, though, to be honest - this is a situation where we are collectively willing to forgo a little readability for performance.
I realize these may be minor micro-optimizations, but they've been shown to add up in my anecdotal experience when modeling several thousands of objects.
The for loop you have suggested is about as good as you're going to get. A couple optimizations you could take would be to avoid property lookups:
var objval = obj[field],
instances = schema.collection.instances;
for(x = 0, xl = instances.length; x < xl; ++x) {
objval.push(instances[x].toObject());
}
On a semi-related note, hasOwnProperty() does cause a signficant performance hit (compared to something simpler like field !== undefined).

javascript enum auto-increment?

In objc I can use the enum like this:
typedef enum {
STATE_A = 1,
STATE_B,
STATE_C,
......
STATE_KK = 100,
STATE_FF,
......
STATE_XXX = 99999
} State;
the value of each variable is auto increased (compared to the former one).
but in javascript, I need to:
var State = {
STATE_A: 1,
STATE_B: 2,
STATE_C: 3,
......
STATE_KK: 100,
STATE_FF: 101,
......
STATE_XXX = 99999
}
you see I need to specify all the values for each varible and this is really sick when you
got lots of varible there and it gets even sicker when you try to insert a variable in between so that
you have to ask yourself (what the value it should be ???)
I'm quite new to js and really wants to know if there is a way to use enum in js the way like in other languages
such as objc I mentioned.
Thanks :)
its kind of ugly, but you could do:
var i=1;
var State = {
STATE_A: i++,
STATE_B: i++,
STATE_C: i++
}
How about giving them all an initial value of 0 then setting their values in a loop
var State = {
STATE_A: 0,
STATE_B: 0,
STATE_C: 0,
......
STATE_KK: 0,
STATE_FF: 0,
......
STATE_XXX = 0
}
var count=0;
for(var key in State){
State[key]=count++;
}
You can create your little enum maker that both auto-numbers them and lets you set any values you want (kind of like the features you have in objectiveC:
function makeEnum(list) {
var obj = {}, sequence = 0, current;
for (var i = 0; i < list.length; i++) {
current = i;
if (typeof list[i+1] === "number") {
sequence = list[i+1];
i++;
}
obj[list[current]] = sequence++;
}
return(obj);
}
var State = makeEnum(["STATE_A","STATE_B","STATE_C", "STATE_KK", 100, "STATE_LL"]);
Anywhere you put a number in the passed in array, it sets the value of the previous enum value and the sequence then continues from that value.
If I understand correctly your goal is to identify states with numbers in order to make them comparable in enums.
First here is a working fiddle of what I think you meant.
For general enums, here is a nice trick I use:
function createEnum(values){
var res={};
for(var i=0;i<values.length;i++){
res[values[i]]=i;//add the property
}
//Object.freeze(res);//optional to make immutable
return res;
};
This allows the following syntax
var State = createEnum(["STATE_A","STATE_B","STATE_C"]);
This means you don't have to explicitly define an integer value for all the states, one is given. After that you can use it normally
State.STATE_A===State.STATE_B;//returns 1
If you'd like to fill based on a pattern, you can extend this the following way (assuming your syntax):
function createEnumPattern(prefix,range){
var res={},str="a";
for(var i=0;i<range;i++){
var pattern = prefix+"_"+inc_str(str);
res[pattern]=i;//add the property
}
//Object.freeze(res);//optional to make immutable
return res;
}
Where inc_str is from this answer.
So for example
var State = createEnumPattern("State",100);
Will return a State enum with properties like State_aa and so on, if you'd like you can use toUpperCase on it to force the upper case convention you use.

Custom for-loop helper for EmberJS/HandlebarsJS

A small two hours ago I started: Nested HandlebarsJS #each helpers with EmberJS not working
Shortly after I figured an acceptable temporary solution myself, question is still unaswered. My problems didn't stop there though.
I am now trying to make a custom helper which will loop through an array of objects, but exclude the first index - pretty much: for(i = 1; i < length; i++) {}. I've read on websites you have to get the length of your context and pass it to options - considering your function looks like: forLoop(context, options).
However, context is a string rather than an actual object. When you do a .length, you will get the length of the string, rather than the size of the array. When I pass that to options, nothing happens - not too mention browser freezes.
I then first tried to do a getPath before passing it to options, this returns an empty string.
What am I supposed to do instead, I made the for-loop code before for just HandlebarsJS and that worked, but EmberJS doesn't seem to take it, why?
EDIT: I pretty much also followed: http://handlebarsjs.com/block_helpers.html -> Simple Iterators
I solved this myself after trying for a long time.
The HandlebarsJS method (as described on the site) is no longer valid for EmberJS, it's now as follows:
function forLoop(context, options) {
var object = Ember.getPath(options.contexts[0], context);
var startIndex = options.hash.start || 0;
for(i = startIndex; i < object.length; i++) {
options(object[i]);
}
}
Heck, you could even extend the for-loop to include an index-value!
function forLoop(context, options) {
var object = Ember.getPath(options.contexts[0], context);
var startIndex = options.hash.start || 0;
for(i = startIndex; i < object.length; i++) {
object[i].index = i;
options(object[i]);
}
}
This is a working for-loop with variable start index. You use it in your templates like so:
{{#for anArray start=1}}
<p>Item #{{unbound index}}</p>
{{/for}}
Here is how I did it (and it works !!!)
First,
i had in my model a 'preview' property/function, that just return the arrayController in an array :
objectToLoop = Ember.Object.extend({
...
arrayController: [],
preview: function() {
return this.get('arrayController').toArray();
}.property('arrayController.#each'),
...
});
Then, I add a new Handlebars helper :
Handlebars.registerHelper("for", function forLoop(arrayToLoop, options) {
var data = Ember.Handlebars.get(this, arrayToLoop, options.fn);
if (data.length == 0) {
return 'Chargement...';
}
filtered = data.slice(options.hash.start || 0, options.hash.end || data.length);
var ret = "";
for(var i=0; i< filtered.length; i++) {
ret = ret + options.fn(filtered[i]);
}
return ret;
});
And thanks to all this magic, I can then call it in my view :
<script type="text/x-handlebars">
<ul>
{{#bind objectToLoop.preview}}
{{#for this end=4}}
<li>{{{someProperty}}}</li>
{{/for}}
{{/bind}}
</ul>
</script>
And that's it.
I know it is not optimal, so whoever have an idea on how to improve it, PLEASE, make me know :)

Categories

Resources