Remove JS object reference - javascript

Currently I'm solving https://www.hackerrank.com/challenges/the-trigram in JS. When I run the solution against the test case input - it "passes". But when submitting it - it gets Runtime error.
The main idea is I have a class (Trigram), where using the input.split(" ").forEach( ... ) (after normalising the input and stuff) I load all the possible trigrams, compare to a candid and if it occurs more times - save to a var outside the forEach.
In the loop, the objects are initialised within let scope (I'm not sure in the terminology).
After googling around, I've found out that the objects are being referenced for ever (despite let), so garbage collector does not get rid of them. That is why I get Runtime error.
How can I get rid of the unnecessary references?
// not the exact code
function processData(input) {
var candid = new Trigram();
input.split(" ").forEach(function(element, index, array) {
let obj = new Trigram(array[index], array[index+1], array[index+2]); // I guess, by using array[n] I'm using some kind of ultimate referencing
if (magic) {
candid = obj; // with the test case's input it runs twice
}
});
}

Related

Nested javascript arrays: access across module boundaries

I'd be grateful if someone could provide a working example of a nested array populated and accessible across ES6 module boundaries, that is to say with setter and (especially) getter methods called from a dependent module.
No matter which design pattern I base my attempts on, setter methods work fine but getter methods invoked across module boundaries invariably provoke the following:
TypeError: nested_array[at_whatever_depth] is undefined
I am not convinced of polluting potentially simple principles with complex examples, but here is roughly what I'm trying to do.. I'd be mega content with something simpler that actually works..
Previously, the array was populated in the same scope as the code which used it. What follows was an attempt at 'modularising' it. The code simply readies an imported music font ('glyphs') for display.
This particular example goes back to more or less where I started: a state module approach. (Others tried? The slightly more advanced basket and revealing module, and a lot of variations thereon..).
var music_glyphs_store = (function () {
var pub = {};
pub.state = [],
pub.setGlyphByName = function (glyph_name, horiz_adv_x, path) {
pub.state.push(glyph_name);
pub.state[glyph_name] = [];
pub.state[glyph_name]["glyph_name"] = glyph_name;
pub.state[glyph_name]["horiz-adv-x"] = horiz_adv_x;
pub.state[glyph_name]["d"] = path;
},
pub.getGlyphByName = function(glyph_name) {
return pub.state[glyph_name];
}
return pub; // expose externally
})();
export { music_glyphs_store };
The problematic call is to music_glyphs_store.getGlyphByName() and its variants. I know that the glyphs I'm trying to retrieve are stored in the array: the dependent module simply can't access them..
Here's what a typical font element might look like in the original, raw, svg file.
<glyph glyph-name="scripts.sforzato" unicode="" horiz-adv-x="219"
d="M-206.864 126.238c-8.498 -2.679 -12.964 -10.131 -12.964 -17.821c0 -6.455 3.146 -13.0777 9.696 -17.1846c1.8 -1.1369 -9.04799 1.8 139.074 -37.9895l103.026 -27.7105l71.6682 -19.279c12.269 -3.31579 22.358 -6.11053 22.358 -6.25263
c0 -0.142105 -10.089 -2.93684 -22.358 -6.25264l-71.6682 -19.2789l-103.026 -27.7105c-154.231 -41.4474 -137.132 -36.7106 -140.4 -38.8895c-5.625 -3.7263 -8.44299 -9.80721 -8.44299 -15.8892c0 -6.056 2.795 -12.113 8.396 -15.848
c3.147 -2.07201 6.077 -3.08401 9.87399 -3.08401c3.061 0 6.685 0.658005 11.442 1.94801l161.053 43.2942c228.488 61.4133 240.486 64.527 240.486 65.2851c0 0.0888996 -0.164993 0.1455 -0.164993 0.26c0 0.0702 0.0619965 0.1623 0.263 0.297099
c5.63699 3.7421 8.45499 9.80522 8.45499 15.8684c0 6.06316 -2.81799 12.1263 -8.45499 15.8684c-3.17401 2.0842 2.27299 0.521 -46.137 13.5474l-194.447 52.2947l-161.053 43.2947c-4.795 1.316 -8.506 1.94601 -11.581 1.94601
c-1.907 0 -3.57001 -0.243004 -5.093 -0.714005z" />
Here's how the calls are set up:
import { music_glyphs_store } from "./music_glyphs_store.js";
import * as d3 from "d3";
Then (having, at some point, loaded and parsed the raw xml strings from file):
d3.selectAll(note_glyphs.getElementsByTagName("glyph")).each(function(d, i) {
var glyph_name = this.getAttribute("glyph-name");
var horiz_adv_x = this.getAttribute("horiz-adv-x");
var path = this.getAttribute("d");
music_glyphs_store.setGlyphByName(glyph_name, horiz_adv_x, path);
});
Whatever the purpose, the idea is that stored values can later be recovered using calls to the above methods. For example:
console.log("index.js: Recovering " + music_glyphs_store.getGlyphByName("brace446"));
console.log("index.js: Recovering " + music_glyphs_store.getGlyphByName("accidentals.natural.arrowdown"));
console.log("index.js: Recovering " + music_glyphs_store.getGlyphByName("noteheads.s2slash"));
In deference to the ES6 module conventions, I later tried eliminating the duplicate ('superflous') state module wrapper (goal: better selective exposure of inner variables and functions) - but to no avail. Declaring the array root variable at window (global) scope also brings no improvement.
The motivation for all this is a migration of existing code -with conventional html inclusions- to Webpack with it's module export/import approach, thereby also leveraging node.js's strengths. While breaking a lot of previously working code, I'm optimistic about the long-term benefits..
The problem would seem to lie with the visibility/scope of dynamically allocated memory. I begin to wonder if nested arrays can be used in a diverse Webpack context at all. Am I perhaps barking up a dead tree?
I think you are confusing array and objects. Arrays are sequential lists, where the index of each cell is an integer. Your code is pushing glyph_name and unicode onto the state array, which places it in next element in the array, but then you are referencing the array using glyph_name and unicode as the index. I think you want to be using objects instead of arrays. Change the lines:
pub.state = [];
pub.state[glyph_name] = [];
pub.state[unicode] = [];
to
pub.state = {};
pub.state[glyph_name] = {};
pub.state[unicode] = {};
Though incorrect, I'm leaving this answer in place to illustrate what (as pointed out by #Bergi in the comments) qualifies as "array abuse".
The consistently unsettling thing here was that the original code worked fine. It only broke on integration to Webpack. That suggested that structurally, things may be more or less ok, but that in the earlier implementation, there were likely related problems.
With a little experiment, I found I could successfully retrieve array values across module boundaries by enclosing glyph_name in rounded brackets. For example:
pub.getGlyphByName = function(glyph_name) {
return pub.state[(glyph_name)];
},
BUT 1) I don't entirely understand what is happening, and 2) it looks fragile..
The actual (external, dependent module) call would remain as in the original question.
--> Immediate problem solved, but only by abusing the arrays..

Use window to execute a formula instead of using eval

My code need to execute a forumla (like Math.pow(1.05, mainObj.smallObj.count)).
My path is :
var path = mainObj.smallObj.count;
as you can see.
If needed, my code can split all variable names from this path and put it in an array to have something like :
var path = ["mainObj", "smallObj", "count"];
Since I don't want to use eval (this will cause memory leaks as it will be called many times every seconds), how can I access it from window?
Tried things like window["path"] or window.path.
If it is always unclear, let me know.
Thanks in advance for any help.
EDIT: forget to tell that some config are written in JSON, so when we take the formula, it's interpreted as "Math.pow(1.05, mainObj.smallObj.count)" so as a string.
I would say there are better solutions then eval, but it depends how the forumla can be structured. It could be precompiled using new Function (this is also some kind of eval) but allowing it to be called multiple times without the need to recompile for each invocation. If it is done right it should perform better then an eval.
You could do something like that:
var formula = {
code : 'Math.pow(1.05, mainObj.smallObj.count)',
params : ['mainObj']
}
var params = formula.params.slice(0);
params.push('return '+formula.code);
var compiledFormula = Function.apply(window, params);
//now the formula can be called multiple times
var result = compiledFormula({
smallObj: {
count: 2
}
});
You can get the path part reconciled by recursively using the bracket notation:
window.mainObj = { smallObj: { count: 2 } };
var path = ["mainObj", "smallObj", "count"];
var parse = function (obj, parts) {
var part = parts.splice(0, 1);
if (part.length === 0) return obj;
obj = obj[part[0]];
return parse(obj, parts);
};
var value = parse(window, path);
alert(value);
Basically, parse just pulls the first element off the array, uses the bracket notation to get that object, then runs it again with the newly shortened array. Once it's done, it just returns whatever the result of the last run is.
That answers the bulk of your question regarding paths. If you're trying to interpret the rest of the string, #t.niese's answer is as good as any other. The real problem is that you're trusting code from an external source to run in the context of your app, which can be a security risk.

Javascript code causing IE freeze

I have the below code causing Internet Explorer to freeze. It's a project that involves processing student grades as an assignment:
var array1 = StudentGradeAreadHugeList();
var nextArrayItem = function() {
var grade = array1.pop();
if (grade) {
nextArrayItem();
}
};
i hope you can help me with this.
You could show more info about the application you're trying to do. But I believe it's a matter of stack overflow (maybe you're using a big list). So, to overcome that you should modify the "nextArrayItem":
window.setTimeout (nextArrayItem, 0)
The freeze incurring mainly from the big data, but now the Event Loop will handle the Recursion process and not your Call Stack.
This is likely caused by an endless recursion. Be aware of proper handling of return values in IE:
var array1 = StudentGradeAreadHugeList();
var nextArrayItem = function() {
var grade = array1.pop();
if ( grade !== null && typeof(grade) !== "undefined" ) {
nextArrayItem();
}
};
pop() on an empty array will not return boolean false but a typeless "undefined".
There's two problems here:
You might be exceeding the call stack limit
Your if-conditional is set-up incorrectly
For the first issue:
As one of the previous responders mentioned, if you have a very large list you can exceed the limit of the call stack since you need to do a recursive call for each element. While doing setTimeout might work, it feels like a hack-y solution. I think the real issue is that your function is handling the array recursively rather than iteratively. I would recommend re-writing your function using a for-loop.
For the second issue:
Let's say in this case your array was set to [100, 90, 80]. When you invoke nextArrayItem() it will work properly the first two time, but the third time you call nextArrayItem() you are popping off the last remaining item (in this case 100) and your grade will be set to 100 which is a truthy value. Therefore, your if-conditional will pass and your function erroneously try to invoke itself again despite the fact that your array is now empty and the program should now exit the call stack.
I tried testing your code using my example in Chrome and what happens is that it will recurse one too many times and invoke pop on an empty array, which will return undefined.
You can fix this issue by changing the if conditional to check for the last element in the array after you have popped the array.
See revised code:
var nextArrayItem = function() {
var grade = array1.pop();
if (array1[array1.length-1]) {
nextArrayItem();
}
};

Javascript - Array of prototype functions

I'm a javascript newbie so I'm writing ugly code so far sometimes due to my lack of experience and how different it is to the languages I'm used to, so the code I'll post below works, but I'm wondering if I'm doing it the right way or perhaps it works but it's a horrible practice or there is a better way.
Basically, I have a little dude that moves within a grid, he receives from the server an action, he can move in 8 directions (int): 0:up, 1: up-right, 2: right... 7: up-left.
the server will send him this 0 <= action <= 7 value, and he has to take the correct action... now, instead of using a switch-case structure. I created a function goUp(), goLeft(), etc, and loaded them in an array, so I have a method like this:
var getActionFunction = actions[action];
actionFunction();
However, what to set all this up is this:
1) create a constructor function:
function LittleDude(container) {
this.element = container; //I will move a div around, i just save it in field here.
}
LittleDude.prototype.goUp() {
//do go up
this.element.animate(etc...);
}
LittleDude.prototype.actions = [LittleDude.prototype.goUp, LittleDude.prototype.goUpLeft, ...];
//In this array I can't use "this.goUp", because this points to the window object, as expected
LittleDude.prototype.doAction = function(action) {
var actionFunction = this.actions[action];
actionFunction(); //LOOK AT THIS LINE
}
Now if you pay attention, the last line won't work.. because: when i use the index to access the array, it returns a LittleDude.prototype.goUp for instance... so the "this" keyword is undefined..
goUp has a statement "this.element"... but "this" is not defined, so I have to write it like this:
actionFunction.call(this);
so my doAction will look like this:
LittleDude.prototype.doAction = function(action) {
var actionFunction = this.actions[action];
actionFunction.call(this); //NOW IT WORKS
}
I need to know if this is hackish or if I'm violating some sort of "DO NOT DO THIS" rule. or perhaps it can be written in a better way. Since it seems to me kind of weird to add it to the prototype but then treating it like a function that stands on its own.
What you are trying to do is one of the possible ways, but it is possible to make it more simple. Since object property names are not necessary strings, you can use action index directly on prototype. You even don't need doAction function.
LittleDude = function LittleDude(container) {
this.container = container;
}
LittleDude.prototype[0] = LittleDude.prototype.goUp = function goUp() {
console.log('goUp', this.container);
}
LittleDude.prototype[1] = LittleDude.prototype.goUpRight = function goUpRight() {
console.log('goUpRight', this.container);
}
var littleDude = new LittleDude(123),
action = 1;
littleDude[action](); // --> goUpRight 123
littleDude.goUp(); // --> goUp 123
actionFunction.call(this); //NOW IT WORKS
I need to know if this is hackish or if I'm violating some sort of "DO NOT DO THIS" rule. or perhaps it can be written in a better way.
No, using .call() is perfectly fine for binding the this keyword - that's what it's made for.
Since it seems to me kind of weird to add it to the prototype but then treating it like a function that stands on its own.
You don't have to define them on the prototype if you don't use them directly :-) Yet, if you do you might not store the functions themselves in the array, but the method names and then call them with bracket notation:
// or make that a local variable somewhere?
LittleDude.prototype.actions = ["goUp", "goUpLeft", …];
LittleDude.prototype.doAction = function(action) {
var methodName = this.actions[action];
this[methodName](); // calls the function in expected context as well
}

Variable Dependency with knockoutJS

I'm building an application with KnockoutJS with a component that essentially acts as a sequential spreadsheet. On different lines users may define variables or use them to represent a value.
So for example
x =2
x //2
x = 4
x //4
I have this working in the straightforward case of continuing adding new lines. The output function for each line checks and iterates backwards to see if the variable was ever defined previously. If it was it uses the first example it finds and sets that as the value. This works when initially defining the lines, and also works when you edit a line after a previous line has changed.
However, I would like variables to update if a previous definition of that variable has changed, been removed, or been added. That behavior does not exist right now. I have tried adding my own custom dependency handling code using a map to track the variables, but it badly impacted performance. I would like to tap into Knockouts dependency management to solve this, but I'm not sure of the best way to do so. Here is a brief summary of my code structure, I would be happy to add more detail if needed.
calcFramework is the view-model object I bind to the map. It consists of an observable list of Lines, a varMap, and other unrelated properties and functions
Line is a custom object. The relevant code is below
var Line = function (linenum,currline) {
var self = this;
self.varMap = {};
self.input = ko.observable("");
self.linenum = ko.observable(linenum);
self.lnOutput = ko.computed({
read:function(){
return outputFunction(self,self.input());
},
write:function(){},
owner:self
});
};
function outputFunction(self,input) {
try{
var out = EQParser.parse(input,10,self);
return out.toString();
}
catch(ex){
//error handling
}
}
Line.prototype.getVar = function (varName, notCurrentLine) {
if(typeof varName === "undefined"){
return null;
}
//Actually don't want ones set in the current varMap, only past lines
if(varName in this.varMap && notCurrentLine){
return this.varMap[varName];
}
if (this.linenum() > 0) {
var nextLine = calcFramework.lines()[this.linenum() - 1];
return nextLine.getVar(varName,true);
} else {
//eventually go to global
return calcFramework.varMap[varName];
}
};
Line.prototype.setVar = function(varName,value){
this.varMap[varName] = value;
};
SetVar and getVar are passed to eqParser, which gets the value of the expression, calling those functions as needed if a variable is referenced. So the variable value is not explicitly passed to the function and thus knockout does not view it as a dependency. But I'm not sure how I would pass the variable as a parameter without traversing the list every time.
So my question is, given this setup, what is the best way to track changes to a variable assignment (and/or new assignments) and update the lines that reference that variable, while maintaining good performance.
I recognize my question is lengthy and I have attempted to trim out all unnecessary detail. Thanks for your patience in reading.
I would be tempted to use a publish/subscribe model, using something like Peter Higgins' PubSub jquery plugin
Your overall app would subscribe/listen out for lines publishing an event that they have a variable definition. This would store any variable names in a standard javascript hashtable, along with the value. When a variable found event is published by a line, the app would check through all the known variables, and if it finds that it is a change to an existing variable value, it would publish a variable changed event. All the lines would subscribe to that event. They can then check whether they have a variable matching that name, and update the value accordingly.
Here's some untested code to give you an idea of what I mean:
var app = function()
{
var self = this;
self.variables = {};
$.subscribe('/variableAssigned', function (key, value)
{
// I think that this is the best way of checking that there is a variable
// in the object
if(self.variables.hasOwnProperty(key))
{
if(self.variables[key] !== value)
{
$.publish('/variableChanged', [ key, value ]);
}
}
});
}
In your Line object:
$.subscribe('/variableChanged', function (key, value)
{
// loop through varMap and see if any of them need updating.
});

Categories

Resources