I have a pattern with default values which one looks like this:
DataStructure.prototype.modelPattern = {
param1: 0,
param2: 1,
...
param462: 1500
};
This pattern represents the structure of a so called "model". Due to I need more than one model I need to create more of those "modelPattern" objects. They all get saved in an array within the same class:
DataStructure.prototype.models = [];
So this cannot work:
this.models[rightPlace] = this.modelPattern;
... due to this just saves the reference to the "modelPattern" object into the array.
So I need to create new objects of "modelPattern" and save them into the array. I already tried those things:
new modelPattern;
modelPattern.create();
This is my first OOP javascript project so I guess I missed something that causes my problem. I need the solution with the pattern due to I don't want to define that extremely long thing over and over in different methods where I need it.
You should work with functions.
e.g.
function createModelPattern(name, start, end) {
var i, j, model = {};
for(i = start, j = 0; i <= end; i++, j++) {
model[name + i] = j;
}
return model;
}
console.log(createModelPattern("param", 1, 10));
Do you understand the difference between object prototype and instance? The prototype is only useful if you're going to have multiple instances, else you can use a single object (just making sure).
Why not simply store your modelPattern in a separate prototype? It's definitely more modular...
function ModelPatternConstruct () {
this.param1 = 0;
this.param2 = 1;
//etc.
}
You can make modelPatterns based off of the constructor. They will inherit the prototype's values. Finally, if you want your models to be accessible through named keys, you might want to consider an object instead of an array to store them.
DataStructure.prototype.models = {
rightPlace: new ModelPatternConstruct(),
leftPlace: new ModelPatternConstruct()
}
// now you can modify them like you wanted
DataStructure.prototype.models.param1 = 5;
Or if you do the work inside your constructor: (the norm is to do simple key-value assignment inside the prototype function, and to add functions externally with Object.prototype.myFunction = etc...
function DataStructure() {
this.models = {
rightPlace: new ModelPatternConstruct(),
leftPlace: new ModelPatternConstruct()
}
this.models.somePattern = new ModdelPatternConstruct();
}
Related
I'm trying to write implement a graph (the data structure) in Javascript. To do so I have a function called Graph that stores this matrix in a 2D array in an attribute called this.adjMatrix. It also has a bunch of methods.
I also want to create something called a residual graph, which takes a Graph object, creates a copy of this.adjMatrix for itself, and modifies this copy, and saves it in it's own this.adjMatrix attribute.
Now, I want the residual graph to have access to all of Graph's functions as well, so I made Graph a prototype of ResidualGraph. However, this brought about an issue. Here is a look at my implementation:
function ResidualGraph(G) {
this.adjMatrix = G.adjMatrix.slice();
this.idList = G.idList.slice();
this.init = function() {
for (i = 0; i < this.adjMatrix.length; i++) {
for (j = 0; j < this.adjMatrix[i].length; j++) {
if (i != j && G.adjMatrix[i][j] != -Infinity && G.adjMatrix[i][j] != 0) {
this.adjMatrix[j][i] = 0;
};
};
};
};
this.init();
};
ResidualGraph.prototype = new Graph();
G = new Graph();
R = new ResidualGraph();
When the init() method runs (on creation of an instance of ResidualGraph) the instance of ResidualGraph has its this.adjMatrix modified as desired. However, the instance of Graph that was passed in also has its this.adjMatrix modified for some reason. Why does this happen?
So it turns out the issue was not with the prototype! It was simply the fact that .slice() only creates a shallow copies. As a result, the this.adjMatrix in the ResidualGraph was the this.adjMatrixin Graph.
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).
Getting the negative value when i perform the onclick function in javascript
function sun()
{
var d,i;
var t = document.getElementById("table");
var rows = t.getElementsByTagName("tr");
for (i = 0; i < rows.length; i++) {
console.log("inside............." + i);
rows[i].onclick = function() {
d = (this.rowIndex);
console.log(d);
};
}
}
Though I'm not sure it's what's causing the exact issue you're noticing, you've encountered a pretty common JavaScript pitfall here by using a closure (anonymous function) inside of a loop. JavaScript, like many other languages that support functional programming, has the convenient property that functions can "close scope" around any variables visible to them at the time of their creation. So, as you've done there, you can use the value of d (or i) inside your function so long as it can see them when your function is declared.
Something funny happens inside a loop, though: every function you create within the loop shares the same scope, meaning they all share the exact same copies of d and i. As a result, when you click on any of your rows, the values of d and i used will be their values at the end of the loop, not the particular iteration you're targeting.
This is ordinarily fixed using something known as the "generator pattern," where you create a separate function that returns new functions closed over your desired scope. For example, in your code, you might do something like
function generateClickHandler(i, d) {
return function() {
d = (this.rowIndex);
console.log(d);
};
}
function sun()
{
var d,i;
var t = document.getElementById("table");
var rows = t.getElementsByTagName("tr");
for (i = 0; i < rows.length; i++) {
console.log("inside............." + i);
rows[i].onclick = generateClickHandler(i, d);
}
}
The new function generateClickHandler returns a function itself, but the important thing to notice here is that the returned function closes over the local arguments i and d, not the shared i and d values used in the loop — their values get copied when you call generateClickHandler. In this way, your code won't be subject to strange closure effects.
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.
Is there a quick way to "super" deep clone a node, including its properties? (and methods, I guess)
I've got something like this:
var theSource = document.getElementById("someDiv")
theSource.dictator = "stalin";
var theClone = theSource.cloneNode(true);
alert(theClone.dictator);
The new cloned object has no dictator property. Now, say I've got a thousand properties attached to theSource - how can I (non-explicitly) transfer/copy them to the clone?
// EDIT
#Fabrizio
Your hasOwnProperty answer doesn't work properly, so I adjusted it. This is the solution I was looking for:
temp = obj.cloneNode(true);
for(p in obj) {
if(obj.hasOwnProperty(p)) { eval("temp."+p+"=obj."+p); }
}
probably the best way to save a lot of properties is to create a property object in which you can store all properties e.g.
thesource.myproperties = {}
thesource.myproperties.dictator1 = "stalin";
thesource.myproperties.dictator2 = "ceasescu";
thesource.myproperties.dictator3 = "Berlusconi";
...
then you have to copy just one property
theclone.myproperties = thesource.myproperties
otherwise do a for cycle for all properties you have stored
for (p in thesource) {
if (thesource.hasOwnProperty(p)) {
theclone.p = thesource.p;
}
}