force javascript treat variables as strings if not defined - javascript

Imagine we have a function test like this:
function test(input) {
console.log(input);
}
And we can simply call it like this:
test("hello");
Now, my problem is I have a string like this:
test(hello); test(world); test(foo); test(bar);
That I need to run. I use eval to do so, but because variables hello, word, foo, bar, ... are not defined, eval will throw ReferenceError.
I need to somehow force JavaScript to treat all undefined variables as strings. I need it to run like this:
test("hello"); test("world"); test("foo"); test("bar");
Also sometimes there are nested functions.
Is there any way to do this?

Since you have your input as a string - you could just try to replace all ( with (" and all ) with ") in order to transform your vars inside of parentheses into strings.
function test(str) {
console.log(str);
}
var initialString = "test(hello); test(world); test(foo); test(bar);";
var transformedString = initialString.replace(/\((\w+)\)/g, '("$1")');
eval(transformedString);
eval("test(test(test(test(test(hello)))))".replace(/\((\w+)\)/g, '("$1")'));
But definitely, this is not a good solution (as mentioned in comments) but just a brute force approach.
UPDATE: Updated answer to support nested calls.

Related

Is it possible to create functions similarly to how typeof works, as in using a space instead of parentheses?

So, you know typeof, right?
What I want to do is create a function similar to that, and for this example let's just use a simple constructorof thing:
const constructorof = obj => {
return obj.constructor;
};
The syntax for it ends up being like this:
constructorof(someObjectOrWhatever);
But I want it to be like this:
constructorof someObjectOrWhatever;
Is there a way to do this?
No, you cannot create new keywords with custom logic in Javascript. You'll either need a function call, with the logic inside the function, or you'll need to inline the logic instead of calling the function. Either way, constructorof someObjectOrWhatever won't be valid syntax.

What is the reason behind var a = (expression1, expression2) in javascript?

Looking through some JS code I have found something like this:
var a, b;
if (
(a = someFunction1(), b = someFunction2() )
){
...
}
I never found anything like this previously and I do not understand the reason for doing something like this. Therefore I am curious: is the person who has done this out of his mind or am I just not capable to understand his idea.
When I try to check what construct like (expression1, expression2) does, I see that it always returns the value of the second expression:
(5, 6) // 6
('strange', 'things') // 'things'
(4, undefined) // undefined
So if I would be the one writing this code, I would do something like this:
var a = someFunction1(),
b = someFunction2();
if (b){ ... }
Am I correct in my reasoning?
When I try to check what construct like (expression1, expression2) does, I see that it always returns the value of the second expression
Yes. Even without trying out, this is what the comma operator does.
Am I correct in my reasoning?
Yes. Your code does exactly the same thing, but is more readable.
You are correct, that is essentially if(b). The readability of the first version is terrible and does not save on space so it would make no sense for it to be minified like that.
Assigning variables inside of conditional statements is bad practice.

Why does 'onhashchange'in(window) work?

'onhashchange'in(window)
Having in() work is not a surprise, as new(XMLHTTPRequest) or typeof(x) are other examples of this construct, but not having to separate the string and in is.
Is this per ECMAScript specs? It works in Chrome and FF, haven't tested IE.
From what I can tell, there's no difference whether you wrap window in parenthesis or not in this particular instance. Either way, it checks for this member on the window object.
Might be less confusing if you use spaces:
'onhashchange' in (window)
The same as
'onhashchange' in window
in is not a function, but when you remove the spaces I can see how you read it as such. One advantage to wrapping window in parenthesis is that you can then minify the code:
'onhashchange'in(window)
Something you could not do without the parenthesis.
' is a token that ends a string, so a pair of '' are semantically unambiguous, you don't need whitespace after the end of a string for the lexer to know that it has reached the end of a string.
Another way of saying that is that this works for the same reason that 'Hello '+'world' works.
Additionally, in is a keyword, not a function. It seems like you're thinking of () as the "function call operator", but in this case it's just a disambiguating parentheses.
It's like asking "why does 1 +(2) work?" + doesn't become a function just because you follow it with a paren, and similarly the following will work:
function foo(){}
foo
();
Javascript is brittle with its whitespace rules.
I'm not sure if the notation is confusing you (that maybe in() is a method?), but in is one of those elements of JS that few people correctly understand (I didn't really understand it until quite recently). This is a simplified version showing what in does:
var foo = {
'bar':1,
'barbar':2
}
console.log('bar' in foo); //true
console.log('baz' in foo); //false
What makes this all the more confusing is that you can use in inside a for() loop, as if it (in) were an iterator. The way I tend to think of for loops is like this:
for (exp1; condition; exp2) {
/* statements */
}
for (condition) {
/* statements */
}
In other words, the loop will continue until the in condition fails, which will happen when it runs out of members.

Using try-catch to retrieve the value of nested property. Is it an valid approach?

We have an object (referenced by data) and we want to retrieve the value of a nested property. Ideally, we would like to do it like so:
value = data.category3.section2.article4.title;
We cannot do this like so, because the above line throws a reference error if any of the mediate objects (category3, section2, or article4) are not defined (at the corresponding positions) inside the data object.
Now, to nullify any potential reference errors that might be thrown, we could just place the above line inside a try-catch statement:
try {
value = data.category3.section2.article4.title;
} catch (err ) {}
This works! However, I am not confident that relying on try-catch in such a way is a good practice. The alternative solution would be to manually traverse to the desired property value. I have written a compact utility function that accomplishes that:
function get( val, names ) {
names = names.split( '.' );
while ( val && names.length ) { val = val[ names.shift() ]; }
return val;
}
Now we can get the property value like so
value = get( data, 'category3.section2.article4.title' );
So, my question is:
Is the try-catch approach a valid solution? Or are there valid reasons why it should be avoided?
Btw, the try-catch approach is heavily biased in this thread: What's the simplest approach to check existence of deeply-nested object property in JavaScript?
Why not:
var value = data &&
data.category3 &&
data.category3.section2 &&
data.category3.section2.article4 &&
data.category3.section2.article4.title;
That is safe (if any of the objects in the traversal chain are not set, value will be null). That is a little neater than a bunch of if blocks, and avoids (?mis)using exceptions.
Another use of that method to provide a default value on failure:
var value = data &&
data.category3 &&
data.category3.section2 &&
data.category3.section2.article4 &&
data.category3.section2.article4.title || 'default value';
Both are fine. The only major differences between them I can think of are that
The try-catch may cause a debugger to unecessarily halt too often if you tell it to stop on all exceptions.
This is relevant you need to debug code that is swallowing exceptions. For example, some promise libraries wrap all callbacks in a try-catch block.
The string splitting version can't easily cope with properties that contain a dot in them
var x = {'.': {a: 17}};
try{ obj['.'].a }catch(e){}
get(/*???*/)
If you want something robust that avoids both pitfalls I would suggest a function that can (at least optionally) directly receive a list of properties.
get(val, ['prop1', 0, '.', 'category2']);
I think the differences here are going to be mostly contextual - it depends on the data you're trying to access and what you want to do with it.
For example, the second function will return equivalent undefined values for a variety of circumstances, including both data.category3 === undefined and data.category3.section2.article4.title === undefined. Using try/catch here tells you that you have an actual traversal error, rather than a property that hasn't been set, which you might want to handle differently.
Abusing try catch like this is a dirty hack.
Try catch is there to catch exceptions you throw. Exceptions are used for exceptional cases.
In this case both cases are wrong. You should never have to traverse data.category3.section2.article4.title; where every step can fail.
You should simply be able to assert that if data has a category then it should have a section, article and title.
I say refactor the code so you don't have multiple levels that can fail.
I have seen the answers here and I think that the traversing is your best move, but it looks quite bothersome. You can make a function that traverses it for you or you can use the almighty brototype library found at: https://github.com/letsgetrandy/brototype
This way you can do something like this:
if (Bro(data).doYouEven('category3.section2.article4.title')) {
value = data.category3.section2.article4.title;
}
or you can use a callback:
Bro(app).iDontAlways('category3.section2.article4.title')
.butWhenIdo(function(title){
value = title;
});
I think everyone should check this amazing library out, and code with great bro-ness.
If you dislike the brototype, you can indeed use your own get function.

Evaluating functions for transfer in IE8

I need to transfer JavaScript Objects through JSON and transfer it's functions as well. I found a working version of getting the Strings of Functions and transfering them. Then i can evaluate them again.
//Create the function
var myFunction = function(){alert('Hello, my Function!');}
//get the functions String reprensentation
var myFunctionTransferString = myFunction.toString();
//Now we transfered the object and want to have a function back
var myTransferedFunction = eval('(' + myFunctionTransferString + ')');
//call the transfered function
myTransferedFunction();
Here i have a jsfiddle for this: http://jsfiddle.net/bMjug/
This is working in Firefox, Chrome, and Safari as it should (but as you can guess not in that great pieace of microsoft software called Internet Explorer).
At the line where i want to evaluate the function i get the message fn is null or not an object in IE8.
Actually i found a solution for this but i really don't like this solution. If i put the variable declaration into the String i'm evaluating and remove the parantheses because i'm not expecting an object anymore that would do what i want:
eval('var myTransferedFunction = ' + myFunctionTransferString);
But i find this kind of hacked and bad solution.
Does anyone now a better one for this problem?
Thanks in advance
For what it's worth, the problem is caused by JScript incorrectly interpreting this:
(function x() {})
as a FunctionDeclaration and not a FunctionExpression, so doing a statement-eval instead of an expression-eval. Similar to what happens with {} object-literals without the wrapping brackets. You could get around it by doing something to more explicitly push it into parsing an expression, eg:
eval('['+myFunctionTransferString+'][0]');
But seriously don't. Never rely on the string representation of a function, it is not standardised and there are many browser differences.
You couldn't usefully preserve a function even if function decomposition were reliable, since there is much more to a function than the textual representation of its source. The closures it includes cannot be represented, and closures are ever-more common in real-world JavaScript.
I'm afraid there is no cheap way to serialise/re-instantiate JavaScript objects in general. The JSON subset is the reliable subset, the rest you'll have to code your own ad hoc serialisation formats for.
Functions are not part of the JSON specification. Remember the JSON specification is a subset of JavaScript's syntax.
So your 'hacked' solution is actually the more correct one.
Heres some hacked solutions:
var fn = function() { alert("some text"); }
var fnFromString = new Function("return " + fn.toString()); // function anonymous() { return function() { ... } }
fnFromString = fnFromString(); // function() { alert("some text"); }
and if you executing script immediately:
eval("(" + fn.toString() + ")()"); // fn executed.

Categories

Resources