example of javascript's eval not being evil? - javascript

I read some stackOverflow questions and answers more then ten times per day, and... it looks its first time i feel its okey to post something, as i didnt find accurate enought answer.
Im writing some code in nodeJS. Its web interface for big softswitch based on custom asterisk, where in one place i need to get data from post message from website.
The problem is, that that post message containts numerous info named in fashion:
peer1
peer2
peer3
peer4 etc
Instead of dealing with every single one, i did a loop:
var array = [];
var i = 0;
while (typeof eval("req.body.peer" + i) !== 'undefined' && eval("req.body.peer" + i) !== '') {
console.log('petla wisielca');
//console.log(eval("req.body.peer" + i));
array.push(eval('req.body.peer' + i));
i++;
}
Number filled inputs (actually its html select) is variable.
After creating that array, I deal with rest of things (write peers to file etc) in traditional, non-eval loops.
Am i missing something here, or it's proper way of dealing with such situation?
Thanks in advance!
EDIT:
Looks like i had some kind brain malfunction :).
Solution is very easy,
as kyle cleared it out, to access object variables and for example iterate, all is needed is to use [].
Solution:
var array = []
var i = 0
while (req.body['peer' + i]) {
array.push(req.body['peer' + i])
i++
}
Thanks once more Kyle.

JavaScript objects can be accessed like they're associative arrays:
var array = []
var i = 0
while (req.body['peer' + i]) {
array.push(req.body['peer' + i])
i++
}

Use of eval is ever evitable, i wrote a plugin that make some dynamic calls of functions, you can check how you can access the object without using eval:
https://github.com/HaSuKrOnOs/jquery-dynFn

Related

How to change variable values in an array of variables in JS

Not sure if this is possible to even do so I'll give it a quick shot and see if anyone has any solutions, ahem.
Is there any way I could store these variables into an array, and change them through the array as such;
function themepreviewchange() {pretaskbartxt=curcolsch[0];pretaskbartxtprs=curcolsch[1];preactivetitle=curcolsch[2];preinactivetitle=curcolsch[3];pretbgradinactive1=curcolsch[4];
pretbgradinactive2=curcolsch[5];pretbgradactive1=curcolsch[6];pretbgradactive2=curcolsch[7];cpwhite=curcolsch[8];cplightg=curcolsch[9];cpsilver=curcolsch[10];cpmidgray=curcolsch[11];
cpgray=curcolsch[12];cpblack=curcolsch[13];cpblue=curcolsch[14];cpprussian=curcolsch[15];cpwincyan=curcolsch[16];cpyellow=curcolsch[17];cpfont=curcolsch[18];cphover=curcolsch[19];
cpatext=curcolsch[20];preinvert=curcolsch[21];shuffleflop=curcolsch[22];discheckinv=curcolsch[23];enacheckinv=curcolsch[24];invcheckinv=curcolsch[25];prespritesheet=github+curcolsch[26];
cwpp=curcolsch[27]}
var settings = pretaskbartxt,pretaskbartxtprs,preactivetitle,preinactivetitle,pretbgradinactive1,pretbgradinactive2,pretbgradactive1,pretbgradactive2,cpwhite,cplightg,cpsilver,cpmidgray,
cpgray,cpblack,cpblue,cpprussian,cpwincyan,cpyellow,cpfont,cphover,cpatext,preinvert,shuffleflop,discheckinv,enacheckinv,invcheckinv,prespritesheet,cwpp,currentcolour
And just do a for loop?
for(var i=0; i<curcolsch.length; i++){settings[i]=curcolsch[i]}
The current result just ends up changing the value of that number in the array, and just changes it to the same thing as the current position in the curcolsch array. So my question is; how would I go about using a quicker route than just spamming the same set of variables with one step up in the array like I addressed above?
Just to be clear I'm not completely insane with the variable count problem, the whole reason i'm asking is so I can get rid of them.
Hoping this isn't your homework assignment....
let settings = {
pretaskbartxt: curcolsch[0],
pretaskbartxtprs: curcolsch[1],
...
cwpp: curcolsch[27],
};
for (const aThing in settings) {
console.log(`value of ${aThing} is ${settings[aThing]}`);
}
Should give you the basic idea....
I was hoping for a quick straight forward answer without the need to rewrite half my code, so I've just ended up removing all my variables in a replacement for a single array so I can switch easier and it's more compact + better than any other solution.
var preactive = [undefined,undefined,'--preactivetitle','--preinactivetitle',undefined,undefined,
undefined,undefined,'--prewhite','--prelightg','--presilver','--premidgray','--preblack',
'--preblue','--preprussian',undefined,'--preyellow','--prefont','--prehover',undefined,
'--preinvert']
function themepreviewchange() { precolsch = undefined; precolsch = schemes[themecurrent]
for(var i = 0; i<preactive.length; i++){docelem.style.setProperty(preactive[i], precolsch[i])}
gradient = "linear-gradient(90deg, " + precolsch[4] + "," + precolsch[5] + ")";

Creating and populating a json object

I need to construct and populate a json object with values coming from a method.
A bit of background to this: I'm searching pdf documents with a designated keyword and if I find any match, for each match I need to save:
-the whole sentence where the match is found
-the search term (defined elsewhere: the search term is always the same, so it's really redundant here, but I might need it in the json object that's why I'm including it)
-the result (which is the index where the search term is found in a whole sentence and it should be an integer)
So, here is some code.
I have this function call inside a loop (the loops goes through the pages and then there is a second loop that goes through the text):
for(var i = 0; i < items.length; i++){
lineWithResult = searchPdf(block.str);
if(lineWithResult != null){
console.log(lineWithResult + " wordCounter is " + wordCounter);
}
}
and the function itself:
function searchPdf(toSearch){
var result = toSearch.toLowerCase().indexOf(searchTerm);
if(result >=0){//if match is found
wordCounter++;
//console.log("toSearch " + toSearch + " result is " + result + " wordCounter " + wordCounter);
return toSearch;
}
else{//if match not found
return null;
}
}
SO I need to construct a json object that at each iteration takes in the parameters discussed above:
So, what would be the best way - I'm a bit rusty with json?
I think I would start by creating an empty object like so (if that's even a valid definition):
var searchResult = {"Line" : "", "SearchTerm" : "", "Result" : ""}
If the above is right, where do I define the object and how do I fill it up with the relevant values? Bear in mind that there will be a lot of Lines, one search term and a lot of Results because the documents (a pdf) which I will use are quite big and can returns lots of matches
thanks
With saying something like that:
var searchResult = {"Line" : "", "SearchTerm" : "", "Result" : ""}
You have already defined the object. JavaScript (at this point) is prototypical, not a "class" based language. JSON in JavaScript is not much more than just a plain JavaScript object. If you want to to create multiple objects of that kind, you have various options. I recommend you to read about JS Object creational patterns.
Here is a good link.
That being said, you could do something like that:
// ... maybe inside a function
return {
line: myLineValue,
searchTerm: mySearchtermValue,
result: myResult
}
There is no need to init something with empty values; you just create the object with the curly brackets.
Hope this makes sense to you; if not, let me know in the comments, and I will try to improve my answer. :-)

Delete multiple documents

The following code is working but extremely slow. Up till the search function all goes well. First, the search function returns a sequence and not an array (why?!). Second, the array consists of nodes and I need URI's for the delete. And third, the deleteDocument function takes a string and not an array of URI's.
What would be the better way to do this? I need to delete year+ old documents.
Here I use xdmp.log in stead of document.delete just te be safe.
var now = new Date();
var yearBack = now.setDate(now.getDate() - 365);
var date = new Date(yearBack);
var b = cts.jsonPropertyRangeQuery("Dtm", "<", date);
var c = cts.search(b, ['unfiltered']).toArray();
for (i=0; i<fn.count(c); i++) {
xdmp.log(fn.documentUri(c[i]), "info");
};
Doing the same with cts.uris:
var now = new Date();
var yearBack = now.setDate(now.getDate() - 365);
var date = new Date(yearBack);
var b = cts.jsonPropertyRangeQuery("Dtm", "<", date);
var c = cts.uris("", [], b);
while (true) {
var uri = c.next();
if (uri.done == true){
break;
}
xdmp.log(uri.value, "info");
}
HTH!
Using toArray will work but is most likely were your slowness is. The cts.search() function returns an iterator. So All you have to do is loop over it and do your deleting until there is no more items in it. Also You might want to limit your search to 1,000 items. A transaction with a large number of deletes will take a while and might time out.
Here is an example of looping over the iterator
var now = new Date();
var yearBack = now.setDate(now.getDate() - 365);
var date = new Date(yearBack);
var b = cts.jsonPropertyRangeQuery("Dtm", "<", date);
var c = cts.search(b, ['unfiltered']);
while (true) {
var doc = c.next();
if (doc.done == true){
break;
}
xdmp.log(fn.documentUri(doc), "info");
}
here is an example if you wanted to limit to the first 1,000.
fn.subsequence(cts.search(b, ['unfiltered']), 1, 1000);
Several things to consider.
1) If you are searching for the purpose of deleting or anything that doesnt require the document body, using a search that returns URIs instead of nodes can be much faster. If that isnt convenient then getting the URI as close to the search expression can achieve similar results. You want to avoid having the server have to fetch and expand the document just to get the URI to delete it.
2) While there is full coverage in the JavaScript API's for all MarkLogic features, the JavaScript API's are based on the same underlying functions that the XQuery API's use. Its useful to understand that, and take a look at the equivalent XQuery API docs to get the big picture. For example Arrays vs Iterators - If the JS search API's returned Arrays it could be a huge performance problem because the underlying code is based on 'lazy evaluation' of sequences. For example a search could return 1 million rows but if you only look at the first one the server can often avoid accessing the remaining 999,999,999 documents. Similarly, as you iterate only the in scope referenced data needs to be in available. If they had to be put into an array then all results would have to be pre-fetched and put put in memory upfront.
3) Always keep in mind that operations which return lists of things may only be bounded by how big your database is. That is why cts.search() and other functions have built in 'pagination'. You should code for that from the start.
By reading the users guides you can get a better understanding of not only how to do something, but how to do it efficiently - or even at all - once your database becomes larger than memory. In general its a good idea to always code for paginated results - it is a lot more efficient and your code will still work just as well after you add 100 docs or a million.
4) take a look at xdmp.nodeUrl https://docs.marklogic.com/xdmp.nodeUri,
This function, unlike fn.documentUri(), will work on any node even if its not document node. If you can put this right next to the search instead of next to the delete then the system can optimize much better. The examples in the JavaScript guide are a good start https://docs.marklogic.com/guide/getting-started/javascript#chapter
In your case I suggest something like this to experiment with both pagination and extracting the URIs without having to expand the documents ..
var uris = []
for (var result of fn.subsequence(cts.search( ... ), 1 , 100 )
uris.push(xdmp.nodeUri(result))
for( i in uris )
xdmp.log( uris[i] )

Dynamically define variable name and assigning value in Google Apps Script

I`m writing a script to generate a form in Google Apps Script.
The idea is, that the user should select his/her name from a dropdown list, and then be transferred to the question block for him/her.
Although the questions are the same, there are slight changes in the choices if the dropdowns for some of the questions.
I have an array with the names of the users, and I've defined the questions for every single user.
This is not ideal, as if there is any change in the questions I have to rewrite every block oone by one.
I want to use a loop which generates the question blocks by creating the variables names using the array of the usernames.
I tried the following (this is not the actual code, but throws the same error)
for (a=0; a < 10; a++)
{
eval('var beginning'+a);
}
for (b=0;b<10; b++)
{
eval('beginning' + b) = 1;
}
The first for loop runs fine, but when I try to assign any value it throws an error. (I use here two for loops for debugging only.)
E.g.:
eval('beginning' + b) = 1; //Throws: We're sorry, a server error occurred. Please wait a bit and try again.
eval('beginning' + b + '= 1;'); //Throws: We're sorry, a server error occurred. Please wait a bit and try again.
eval('beginning' + b = 1); //Throws: Invalid assignment left hand side. (line 1, file "Code")
Using eval like this is also fine: choices = eval('lCountries' + Names[i]).getChoices();.
How can I assign values to these variables in a for loop?
Thank you very much in advance.
As far as I read up so far, eval() is almost always a bad choice, should be handled with caution and mostly never used. Using dynamic variables in such way is also a bad programming logic. I've never seen a case where it is a must, and your case obviously isn't. You can easily get around it with an object, just define a generic object var myVariables = {}, and then start assigning its properties dynamically for your variables.
var myVariables = {};
myVariables[ "beginning" ] = 1;
for( i = 0; i < 10; i++){
myVariables[ ("beginning" + i) ] = i;
}
Logger.log( myVariable[ "beginning5" ] ); //Loggs 5

How to store integer indexed data in Javascript?

I'm coming from working in PHP for many years and having trouble wrapping my head around creating some more complicated data structures in JS for objects that are integer IDed. I need to build an object the stores these simpler objects hierarchically keyed on their integer ids. So if I have the following objectes each of which has a unique integer id:
section, element, item, entry
in php I would do something like
$arr[$section_id][$element_id][$item_id][$entry_id] = $entry;
In javascript this does not work. I know I could technically wrap those IDs in quotes to force it but that seems like a bad idea. Similarly I could create an object and use the quoted integer approach but again that seems hacky.
Right now I am storing the data in regular integer indexed arrays and then using caolan's async detect to look up a particular member by ID. This works but seems extremely messy compared to the php equivalent. I'm hoping there's a cleaner way to do this in JS.
TIA!
since javascript cannot save an array with string index, i use these :
var namespace = function(name, separator, container){
var ns = name.split(separator || '.')
, o = container || window
, i = 0;
while (i++ < ns.length) o = o[ns[i - 1]] = o[ns[i - 1]] || {};
return o;
}
namespace(arr + '.' + section_id + '.' + element_id + '.' + item_id + '.' + entry_id) = entry;
// ex : namespace('arr.1.3.2.6') will product arr.1.3.2.6 object
This is a little ugly, but it will get you pretty close to what you want.
You can add a method to the JavaScript Array class like so:
Array.prototype.g = function(index) {
if (this[index] == undefined) {
this[index] = [];
}
return this[index];
}
Then, to set something you would do this:
var test = [];
test.g(5).g(7)[5] = 1;
Unfortunately, for the last entry you'd have to remember to use the regular notation to set the value.
You would retrieve it like you expect:
test[5][7][5]; //1
Obviously I just pulled g out of thin air, you could come up with your own function name.
Disclaimer: People tend to frown on extending the built in types using the prototype chain, but as far as I know most major frameworks no longer do this so unless you or some third party JS is using the same name to extend Array somewhere else you should be fine.

Categories