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.
Related
Currently I am using the following to evaluate variables that are placed in strings at runtime:
newVal = eval("`" + newVal + "`");
So if I have the string:
"Hello from channel: ${erpVars["CommandChannel"]["name"]}"
And erpVars["CommandChannel"]["name"] has value home, then the resulting string is:
Hello from channel: home
There are other objects than just erpVars that could be holding matching values for the string, but this is just one example. It's also important to note that each string could have more than one variable that needs replacing.
I am trying to achieve the same thing without using eval(), as some of the variable values come from user input.
Your case sounds super nasty (you should never ever use eval in JS! It poses a major security threat! also it looks weird that you want to replace this sort of a string) and perhaps if you told me more about where you get your inputs from and in what form, then maybe we could find together a much better solution for this. On that note, this is how I would solve your issue in its current form.
const newVal = 'Hello from channel: ${erpVars["CommandChannel"]["name"]}';
const strings = {
erpVars: {
CommandChannel: {
name: "home"
}
}
};
const vars = newVal.match(/\$\{.+?\}/g);
let result = newVal;
vars.forEach(v => {
let valuePath = '${erpVars["CommandChannel"]["name"]}'.match(/[\w\d]+/g).join('.');
result = result.replace(v, _.get(strings, valuePath));
});
console.log(result);
Note that I'm skipping here the edge scenarios, like getting a null result from the newVal.match when there are no variables in the newVal, but that's easy to handle.
Also note that over here i'm using the lodash library in _.get() (https://lodash.com/docs/4.17.15#get). It's super popular for this kind of small tasks. Of course there are really a lot of other tools that allow you to extract a value based on a property path like erpVars.CommandChannel.name that is stored in the valuePath variable, including a crazy amount of instructions that tell you how to do it yourself.
I am new on this website, and I am also new at Javascript.
What I would do is get a value from a link, eg:
http://bricks.couponmicrosite.net/JavaBricksWeb/LandingPage.aspx?O=107905&C=MF&CPT=qwbc74g7HdLtKVVQ1oNe&P=test&tqnm=td3ffdn764156741
I need to take this value: O=107905, if it is only one code I need to run a file (file A),
if it look like this: O=107905~107906, then I need to run a different file (file B).
What I thought is create a function with javascript where if it is (~) is missing, then will be used the file A, if there is one or more than one of (~) then the file B will start to work.
Many thanks in advance!
Well. We really do encourage you to provide your own code first before providing solutions, but this is a fairly simple problem in javascript. Here's my take on it.
The first problem you have to solve is actually getting the query string parameters in a meaningful format. Here I create an object that uses the query string keys as the object keys (IE 9+ only because of the forEach)
var tmpObject = {}
location.search.substr(1).split('&').forEach(function(item){
var o = item.split('=');
tmpObject[o.shift()] = o.shift();
});
Then it's just a matter of making sure the query string contained the target object (in this case "O") and determine if there is more than one.
if(tmpObject.hasOwnProperty('O') && tmpObject.O.split('~').length > 1) {
console.log('return multiple files');
} else {
console.log('return one file');
}
Try this
var url = "http://bricks.couponmicrosite.net/JavaBricksWeb/LandingPage.aspx?O=107905&C=MF&CPT=qwbc74g7HdLtKVVQ1oNe&P=test&tqnm=td3ffdn764156741";
var search = url.substring(url.indexOf("?")+1);
var map={};
search.forEach(function(val){var items=val.split("="); map[items[0]]=items[1];});
if (map["O"].indexOf("~") != -1)
{
//O value has ~ in it
}
else
{
//O has no ~ in it
}
Possible solution to get the paramter would be there : How to get the value from the GET parameters?
Once you have the parameter value, you can for sure look if you find '~' with String.prototype.indexOf.
String.prototype.indexOf returns the position of the string in the other string. If not found, it will return -1.
In Javascript what is the best way to handle scenarios when you have a set of arrays to perform tasks on sets of data and sometimes you do not want to include all of the arrays but instead a combination.
My arrays are labeled in this small snippet L,C,H,V,B,A,S and to put things into perspective the code is around 2500 lines like this. (I have removed code notes from this post)
if(C[0].length>0){
L=L[1].concat(+(MIN.apply(this,L[0])).toFixed(7));
C=C[1].concat(C[0][0]);
H=H[1].concat(+(MAX.apply(this,H[0])).toFixed(7));
V=V[1].concat((V[0].reduce(function(a,b){return a+b}))/(V[0].length));
B=B[1].concat((MAX.apply(this,B[0])-MIN.apply(this,B[0]))/2);
A=A[1].concat((MAX.apply(this,A[0])-MIN.apply(this,A[0]))/2);
D=D[1].concat((D[0].reduce(function(a,b){return a+b}))/(D[0].length));
S=S[1].concat((S[0].reduce(function(a,b){return a+b}))/(S[0].length));
}
It would seem counter-productive in this case to litter the code with tones of bool conditions asking on each loop or code section if an array was included in the task and even more silly to ask inside each loop iteration with say an inline condition as these would also slow down the processing and also make the code look like a maze or rabbit hole.
Is there a logical method / library to ignore instruction or skip if an option was set to false
All I have come up with so far is kind of pointless inline thing
var op=[0,1,1,0,0,0,0,0]; //options
var L=[],C=[],H=[],V=[],B=[],A=[],D=[],S=[];
op[0]&&[L[0]=1];
op[1]&&[C[0]=1,console.log('test, do more than one thing')];
op[2]&&[H[0]=1];
op[3]&&[V[0]=1];
op[4]&&[B[0]=1];
op[5]&&[A[0]=1];
op[6]&&[A[0]=1];
It works in that it sets only C[0] and H[0] to 1 as the options require, but it fails as it needs to ask seven questions per iteration of a loop as it may be done inside a loop. Rather than make seven versions of the the loop or code section, and rather than asking questions inside each loop is there another style / method?
I have also noticed that if I create an array then at some point make it equal to NaN rather than undefined or null the console does not complain
var L=[],C=[],H=[],V=[],B=[],A=[],D=[],S=[];
L=NaN;
L[0]=1;
//1
console.log(L); //NaN
L=undefined;
L[0]=1
//TypeError: Cannot set property '0' of undefined
L=null
L[0]=1
//TypeError: Cannot set property '0' of null
Am I getting warmer? I would assume that if I performed some math on L[0] when isNaN(L)===true that the math is being done but not stored so the line isn't being ignored really..
If I understand what you want I would do something like this.
var op = [...],
opchoice = {
//these can return nothing, no operation, or a new value.
'true': function(val){ /*operation do if true*/ },
'false': function(val){ /*operation do if false*/ },
//add more operations here.
//keys must be strings, or transformed into strings with operation method.
operation: function(val){
//make the boolean a string key.
return this[''+(val == 'something')](val);
}
};
var endop = [];//need this to prevent infinite recursion(loop).
var val;
while(val = op.shift()){
//a queue operation.
endop.push(opchoice.operation(val));
}
I'm sure this is not exactly what you want, but it's close to fulfilling the want of not having a ton of conditions every where.
Your other option is on every line do this.
A = isNaN(A) ? A.concat(...) : A;
Personally I prefer the other method.
It looks like you repeat many of the operations. These operations should be functions so at least you do not redefine the same function over and over again (it is also an optimization to do so).
function get_min(x)
{
return +(MIN.apply(this, a[0])).toFixed(7);
}
function get_max(x)
{
return +(MAX.apply(this, a[0])).toFixed(7);
}
function get_average(x)
{
return (x[0].reduce(function(a, b) {return a + b})) / (x[0].length);
}
function get_mean(x)
{
return (MAX.apply(this, x[0]) - MIN.apply(this, x[0])) / 2;
}
if(C[0].length > 0)
{
L = L[1].concat(get_min(L));
C = C[1].concat(C[0][0]);
H = H[1].concat(get_max(H));
V = V[1].concat(get_average(V));
B = B[1].concat(get_mean(B));
A = A[1].concat(get_mean(A);
D = D[1].concat(get_average(D));
S = S[1].concat(get_average(S));
}
You could also define an object with prototype functions, but it is not clear whether it would be useful (outside of putting those functions in a namespace).
In regard to the idea/concept of having a test, what you've found is probably the best way in JavaScript.
op[0] && S = S[1].concat(get_average(S));
And if you want to apply multiple operators when op[0] is true, use parenthesis and commas:
op[3] && (V = V[1].concat(get_average(V)),
B = B[1].concat(get_mean(B)),
A = A[1].concat(get_mean(A));
op[0] && (D = D[1].concat(get_average(D)),
S = S[1].concat(get_average(S)));
However, this is not any clearer, to a programmer, than an if() block as shown in your question. (Actually, many programmers may have to read it 2 or 3 times before getting it.)
Yet, there is another solution which is to use another function layer. In that last example, you would do something like this:
function VBA()
{
V = V[1].concat(get_average(V));
B = B[1].concat(get_mean(B));
A = A[1].concat(get_mean(A));
}
function DS()
{
D = D[1].concat(get_average(D));
S = S[1].concat(get_average(S));
}
op = [DS,null,null,VBA,null,null,...];
for(key in op)
{
// optional: if(op[key].hasOwnProperty(key)) ... -- verify that we defined that key
if(op[key])
{
op[key](); // call function
}
}
So in other words you have an array of functions and can use a for() loop to go through the various items and if defined, call the function.
All of that will very much depend on the number of combinations you have. You mentioned 2,500 lines of code, but the number of permutations may be such that writing it one way or the other will possibly not reduce the total number of lines, but it will make it easier to maintain because many lines are moved to much smaller code snippet making the overall program easier to understand.
P.S. To make it easier to read and debug later, I strongly suggest you put more spaces everywhere, as shown above. If you want to save space, use a compressor (minimizer), Google or Yahoo! both have one that do a really good job. No need to write your code pre-compressed.
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
}
I have a function e.g.
var test = function () {alert(1);}
How can I get the body of this function?
I assume that the only way is to parse the result of test.toString() method, but is there any other way? If parsing is the only way, what will be the regex to get to body? (help with the regex is extremly needed, because I am not familiar with them)
IF(!!!) you can get the toString(), then you can simply take the substring from the first indexOf("{") to the lastIndexOf("}"). So, something like this "works" (as seen on ideone.com):
var test = function () {alert(1);}
var entire = test.toString(); // this part may fail!
var body = entire.substring(entire.indexOf("{") + 1, entire.lastIndexOf("}"));
print(body); // "alert(1);"
2015 update
Upon revisiting the state of function decompilation, it can said that it's generally safe in certain well-considered use cases and enviroments (e.g: Node.js workers with user defined functions).
It should be put in the same bucket as eval, which is a powerful tool that has its place, but should only be used on rare occasions. Think twice, that's my only advice.
The conclusions from Kangax's new research:
It's still not standard
User-defined functions are generally looking sane
There are oddball engines (especially when it comes to source code
placement, whitespaces, comments, dead code)
There might be future oddball engines (particularly mobile or unusual
devices with conservative memory/power consumption)
Bound functions don't show their original source (but do preserve
identifier... sometimes)
You could run into non-standard extensions (like Mozilla's expression
closures)
ES6 is coming, and functions can now look very different than
they used to
Minifiers/preprocessors are not your friend
"function decompilation" — a process of getting
string representation of a Function object.
Function decompilation is generally
recommended against, as it is a
non-standard part of the language, and
as a result, leads to code being
non-interoperable and potentially
error-prone.
#kangax on comp.lang.javascript
Simplest Use-Case
If you just want to execute the body of the function (e.g. with eval or using the Worker API), you can simply add some code to circumvent all the pitfalls of extracting the body of the function (which, as mentioned by others, is a bad idea in general):
'(' + myFunction + ')()';
I am using this trick in this Worker-related JSFiddle.
Complete Function Serialization With Accurate Stacktrace
I also wrote a more complete library that can:
Serialize any kind of function to string
Be able to send that string representation anywhere else, execute it with any custom arguments, and be able to reproduce the original stacktrace
Check out my CodeBuilder code here.
Note that much of the code takes care of making sure that we get an accurate stacktrace, wherever we execute the serialized function at a later point in time.
This fiddle demonstrates a simplified version of that logic:
Use JSON.stringify to properly serialize the function (that comes in handy when, e.g., we want to make it part of a bigger serialization "data package").
We then wrap it in one eval to un-escape the "JSON-ish"-escaped string (JSON does not allow functions + code, so we must use eval), and then in another eval to get back the object we wanted.
We also use //# sourceMappingURL (or the old version //# sourceMappingURL) to show the right function name in the stacktrace.
You will find that the Stacktrace looks Ok, but it does not give you the correct row and column information relative to the file that we defined the serialized functions in, which is why my Codebuilder makes use of stacktracejs to fix that.
I use the CodeBuilder stuff in my (now slightly dated) RPC library where you can find some examples of how it is used:
serializeInlineFunction example
serializeFunction example
buildFunctionCall example
extending #polygenelubricants' answer:
using: .toString()
Testee:
var y = /* olo{lo} */
/* {alala} */function/* {ff} */ x/*{s}ls{
}ls*/(/*{*{*/)/* {ha-ha-ha} */
/*
it's a function
*/
{
return 'x';
// }
}
/*
*/
By indexOf and lastIndexOf:
function getFunctionBody(fn) {
function removeCommentsFromSource(str) {
return str.replace(/(?:\/\*(?:[\s\S]*?)\*\/)|(?:([\s;])+\/\/(?:.*)$)/gm, '$1');
}
var s = removeCommentsFromSource( fn.toString() );
return s.substring(s.indexOf('{')+1, s.lastIndexOf('}'));
};
getFunctionBody(y);
/*
"
return 'x'
"
*/
used: rm comments from js source
This code provides the body when using ES6 arrow functions like var testFn=(q)=>q+1;
function getFunctionBody(test){
var entire = test.toString(); // note: not safe-guarded; this part may fail like this!
return entire.substring((entire.indexOf("{")+1)||(entire.indexOf("=>")+2), entire.lastIndexOf("}")!==-1?entire.lastIndexOf("}"):entire.length);
}
//testing/showcase code
var tests = [
function () {alert(1);},
()=>{return 1;},
q=>q+1
];
for (var i=0;i<tests.length;i++){
console.log(tests[i],getFunctionBody(tests[i]));
}
I originally submitted this code as an edit to polygenelubricants accepted answer, but it was rejected as the changes were considered to be too drastic.
var fn1 = function() {};
var fn2 = function() { alert("lol!"); };
Function.prototype.empty = function() {
var x = this.toString().match(/\s*function\s*\w*\s*\(.*?\)\s*{\s*}\s*;?\s*/);
return x != null;
};
alert(fn1.empty()); // true
alert(fn2.empty()); // false
'
Solução proposta pelo Paulo Torres no grupo A.P.D.A. no facebook.
you can try this functiion:
function extractFunctionBody(fn) {
var reg = /function \((.*)\)[ ]?{(.*)}$/g;
var match = reg.exec(fn.toString().replace(/\n/g, ";"));
if (match){
return match[2];
} else {
return "";
}
}
Try this:
/\{(\s*?.*?)*?\}/g.exec(test.toString())[0]
test.toString() will hold your entire declaration.
/{(\s*?.?)?}/g will match everything between your braces