Alternative to eval() javascript [duplicate] - javascript

This question already has answers here:
What are the Alternatives to eval in JavaScript?
(11 answers)
Closed 7 years ago.
I work mainly with javascript, Jquery, knockout, etc
The thing that attracted eval() to me is
var a = 5;
var b = 10;
eval("a+b");
//Gives me output 15
Note: I work in cases where the value of a and b changes dynamically
In my work I'm dealing with a lot of dynamic objects from json, knockout, etc. So eval solves most of my problems.
But as I read I found there are so many issues with eval() like slowing down etc.
I searched a lot and haven't found any substitute for eval() when i have to evaluate equation obtaining as string into equation as object.
Can anyone suggest a plugin or function alternative to eval() keeping in mind the example i have given above
Problem:
I'm creating a Table from Json data using knockout mapping. So that what ever the format of json is the table is generated. I also calculate some field using knockout computed.
Right now I use hard-coded
self.Salary = ko.computed(function(){ return self.salaryEqn() && eval(self.salaryEqn()).toFixed(2); })
self.salaryEqn(salEqnTxt);
I want to execute these equations dynamic. I can create it dynamicaly as string but to eval them is the issue I'm facing.
I want solution for
Is there a way to calculate a formula stored in a string in JavaScript without using eval?
Like a formula
"self.Salary = ko.computed(function(){ return self.salaryEqn() && eval(self.salaryEqn()).toFixed(2); })"

Javascript is a very flexible language in this regard. There are very very few cases where eval() is the right answer to any given question, and it certainly isn't necessary here.
If your a and b variables are part of an object, you can access them with string subscripts:
ie myobj.a could also be referenced as myobj['a'].
From that, you can use a variable for the subscript, and thus you can reference any element in myobj dynamically -- ie:
var myobj = {a : 5, b : 10};
var dynamicProperty1 = 'a';
var dynamicProperty2 = 'b';
//gives 15.
alert( myobj[dynamicProperty1] + myobj[dynamicProperty2] );
No eval() required. You can build the dynamicProperty strings however you wish, so there's virtually infinite flexibility.
If your a and b variables are globals, JS globals in the browser are actually children of the window object, so you can still use this technique even with globals.
ie your global variable a could also be accessed via window.a or window['a'], with the latter option allowing you to do the same dynamicProperty trick described above.
Hope that helps.

do you mean that you want to calculate an equation that you can't know until you've received it?
if so see Calculate string value in javascript, not using eval .
in short:
eval CAN be used sometimes, but only if the equation string comes from a trusted source, and there you need something like evaluating dynamic equations.

maybe using window['var' + num] might be more useful for you. i don't quite understand your question sorry.

If you can collect them under an object like root = {a: 1, b: 2}, then
Object.observe(root, function(newValues) {
res = newValues.object.a + newValues.object.b;
});
can keep your res variable up to date whenever the a or b changes

It looks like you are trying to do dynamic equations created by a user.
For example it could be 'a+b+c' or 'dog+cat', and you don't know.
The best way to handle user-input equations like that is to parse the text into tokens and then translate the tokens into values/operands.
That's a lot of work, but there are pre-rolled solutions. For example, math.js

Check more alternatives to eval in this question and another one here which both might be considered a duplicate...
I understand this is a link only answer, but it will for sure be helpful to others searching for alteratives to eval.

Related

Haxe DOMStringMap values not accessible

I'm trying to access the 'data-*' attributes on an element in the browser in Haxe.
var element = document.getElementById('#someId');
var dataLabel = 'label'; //'data-label'
element.dataset[dataLabel] = 5;
That code (which works in plain javascript) generates two compilation errors in HaxeDevelop.
"String should be Int"
"For function argument 'data'"
How can I access element datasets in Haxe? Is there a known proper way to do it?
I ended up using the Element#getAttribute and Element#setAttribute methods to accomplish the same functionality.
var element = document.getElementById('#someId')
var dataLabel = 'label'; //'data-label'
element.setAttribute('data-' + dataLabel, 5);
I think this is a downside of how the array access operator works in Haxe.
Only abstract types can define array access, as the manual states here.
Haxe's DOMStringMap is just an extern class, so it can't have array access that uses String as a key instead of Int.
Now, there are ways around this. The untyped keyword seen here is one way your initial example could work. untyped isn't recommended though, it's a slippery slope to fragile code that you should avoid whenever possible.

Javascript - generating expressions without operator overloading

I'm using three.js in a js project and I'm trying to calculate if a vector is still in an area like this
var THRESHOLD = 10;
if(!is_in_rect(camera.position - forward * THRESHOLD)))
// do something
where camera.position and foward are THREE.Vector3 objects.
The problem with the approach above, although very readable, is that it's not working since js doesn't support operator overloading. I have to write something like
if(!in_rect(camera.position.clone().add(forward.clone().multiplyScalar(THRESHOLD)))
which looks kinda ugly to me.
Is there any other idiomatic way of doing this in js that I'm missing?
From the page you linked to:
.addScaledVector ( v, s )
Adds the multiple of v and s to this vector
so a bit better is:
camera.position.clone().addScaledVector(forward,THRESHOLD)
Also, there's no real reason to clone forward, as that won't be changed.
If I'm following what #T.J. is saying, and you want something more general, than my answer would be no, if idomatic means using + and -, if we're strictly sticking to JS. You could build your own framework to make things idomatic, such as a general addition operator:
var add = function(x,y):
try {
var sum = x + y;
if ( s != undefined ) { return sum; }
#otherwise
sum = x.clone().add(y);
} catch {
#Otherwise threw something
sum = x.add(y) #maybe another exception? nest try/catch.
}
}
But this is a lot of work, as you would have to type check a lot since JS can add up stuff with impunity. Just trying to return x+y will often be undefined. In my example perhaps testing for add functions before simple additions may be better.
This way you can create the idiom you like, if you think it's worth it, and use your add for everything (instead of + in my example). Probably grow it as you code.
Is there any other idiomatic way of doing this in js that I'm missing?
Not really, no; you'd basically have to write yourself an expression parser, or use one that's already been written.
A couple of notes on that:
Doing that might be a bit easier with ES2015+'s template literals and tagged template functions, since it would do some of the parsing for you. For instance, you might be able to give yourself tag function that would let you write:
if(!is_in_rect(threval`${camera.position} - ${forward} * ${THRESHOLD}`)))
threval would receive an array of the raw strings in that template, followed by the values of camera.position, forward, and THRESHOLD. So you could use that information to build up the sequence. But it would be non-trivial.
You could write yourself a Babel plugin to make your expressions first-class productions, and transpile. The advantage to that is that Babel provides a robust parsing infrastructure and tooling support.

How to get list of all variables defined in the current scope? [duplicate]

This question already has answers here:
Getting All Variables In Scope
(11 answers)
Closed 8 years ago.
I wanted to be able to get a list of all variables in the current scope. I know it may not be possible (ex. 1, 2, 3 but it would really be helpful in simplifying a parsing algorithm for a Node/browser library I'm currently working on.
One thing: it doesn't need to be printed or safe from 'minification'.
I was wanting to be able to figure out what variables were introduced by reading a JS library and dynamically evaling it, finding the difference in state between the two. I know this approach sounds terrible on paper (I'm well acquainted with the hatred of eval), but if there is a better way to find this than just simply parsing the whole library (which is slow for any language other than C/etc.), I'm all ears.
For you all right off crying over the blatant use of eval, I know to use closures to protect the parent scope from modification. I also will be able to prevent changes to the browser display in the eval as well if it is in a browser environment (temporarily change some DOM constructors).
Yes and no. "No" in almost every situation. "Yes," but only in a limited manner, if you want to check the global scope. Take the following example:
var a = 1, b = 2, c = 3;
for ( var i in window ) {
console.log(i, typeof window[i], window[i]);
}
Which outputs, amongst 150+ other things, the following:
getInterface function getInterface()
i string i // <- there it is!
c number 3
b number 2
a number 1 // <- and another
_firebug object Object firebug=1.4.5 element=div#_firebugConsole
"Firebug command line does not support '$0'"
"Firebug command line does not support '$1'"
_FirebugCommandLine object Object
hasDuplicate boolean false
So it is possible to list some variables in the current scope, but it is not reliable, succinct, efficient, or easily accessible.

Any way to assign a variable (not an object property) another variable's value by reference in JavaScript?

So, here's what I need:
var a = 5;
var b = a;
a = 6;
alert(b) // I want this to alert 6 not 5
I've seen questions like How does variable assignment work in JavaScript?, answers like https://stackoverflow.com/a/509614/1117796 and posts like http://hpyblg.wordpress.com/2010/05/30/simulating-pointers-in-javascript/. I do NOT want to use objects/hashes/dictionaries or whatever else you want to call them. I want this done with plain variables containing plain primitive values. Something like the PHP assignment by reference: $b = &$a;. Is it at all possible? Anything that comes near to it?
No that isin't possible to pass simple values as reference in JavaScript.
However JavaScript is a flexible language and you could possibly implement something similar using Object.defineProperty by providing setters and getters that will all work with the same variable. That could work for global variables however, there's no way to completely mimic this behaviour. For instance, since you can't get a reference to the execution scope of functions, you would not be able to emulate this concept for variables declared inside functions.
No, this is not possible as of ECMA Script 5.
No its not possible. And its a boon that this is not allowed in JavaScript.

Obfuscate javascript properties?

I've recently tested UglifyJS and YUI Compressor and noticed something odd.
Both minifiers don't seem to change the names of object properties, only the names of variables and functions.
for instance if I have the following code:
var objName = {first:2, second:4};
alert(objName.first + " " + objName.second);
the names first and second remain unchanged in the minified version.
Why is that?
Since in javascript a new scope is created in a function, you can scope your code in an immediately invoked function.
// scoped
(function() {
var objName = {first:2, second:4};
alert(objName.first + " " + objName.second);
})();
Then using Google's Closure Compiler, if you turn on the "Advanced" optimization it will see that the properties are only used locally, and will obfuscate them.
// result
var a={a:2,b:4};alert(a.a+" "+a.b);
It's because it doesn't know where the object is going to be used. It could be used externally by other code and you wouldn't want your other code to have to change whenever you obfuscate it.
Edit So basically, it's like that to prevent obfuscation from breaking external/internal references to properties that may not be possible to figure out while obfuscating.
Since there are no well defined scoping rules around objects in JavaScript it's impossible to obfuscate the names in a way that is guaranteed to be correct.
For example, if you had the following function:
function f() {
return { first: 'foo', second: 'bar' };
}
In order to obfuscate the property names you would have to nail down all the places that f is called from. Since functions are first-class in JavaScript they can be assigned and passed around in arbitrary ways making it impossible to pin down where f is referenced without actually running the program.
Additionally, JavaScript doesn't have any way for you to specify intent around what's public API and what isn't. Even if the minimizer could reliably determine where the function is called from in the code you give it, there would be no way for it to make the same changes to code that it hasn't seen.
I guess that's because the minifiers would break the object properties. Consider this:
function getProp(ob,name) {
return ob[name];
}
var objName = {first: 2, second: 4};
var prop = getProp(objName, "second");
There's no way for the minifier to know the string literal "second" being an object property. The minified code could look like this then:
function a(b,c){return b[c]}var d={p1:2,p2:4};var e=a(d,"second")
Broken now.
The latest release of uglify (today) has object property mangling, see v2.4.19. It also supports reserved files for excluding both object properties and variables that you don't want mangled. Check it out.
The only public tool so far to obfuscate property and function names (afaik) is the Closure Compiler's Advanced mode. There are a lot of limitations and restrictions, but the end result is generally worth it.
As a passing note: the Dojo Toolkit is compatible (with some minor modifications) with the Closure Compiler in Advanced mode -- arguably the only large-scale public JavaScript library that can be fully obfuscated. So if you are looking at obfuscation to protect your IP, you should look into using Dojo for the task.
http://dojo-toolkit.33424.n3.nabble.com/file/n2636749/Using_the_Dojo_Toolkit_with_the_Closure_Compiler.pdf?by-user=t
Stephen
What about doing something like:
// scoped
(function() {
var objName = {first:2, second:4};
var vA = 'first';
var vB = 'second';
alert(objName[vA] + " " + objName[vB]);
})();
Once objName.first and/or objName.second are referenced enough times, this technique will start to save characters. I can't think of any reason that wouldn't work, but I can't find any minifiers that do it.

Categories