Difference between eval() and eval`` (with backticks) - javascript

So I have came across a curious question that I can't find its answer anywhere and there isn't much documentation on what eval does when you pass to it string literals.
If I do eval("alert(1)") I will get an alert box with 1, however, when I do eval`alert(1)` I just get an array with "alert(1)" I am not sure where that is coming from, isn't it supposed to be treated the same as the previous example?
Also, eval`${1}` returns an array with two empty elements, why?

What you're running into is something to do with tagged templates.
Essentially, you are doing string interpolation and using a function to decide how to create the string. The first argument is expected to be an Array that contains all of the string parts (everything between ${var} declarations). The return of any function used this way is expected to be the string. The reason you are seeing 2 entries is because this function returns a raw format in addition to the one it tried to create using the tag function.

Related

Is there a standard or recommended way to use parts of values in JSON that are separated by colons?

I use this API that returns a JSON with strings in values that are separated by colons.Example:
{
"id": "test:something:69874354",
"whatever": "maybe"
}
In this example I only need the numeric value of the identifier (69874354), but it could be that the value I'm after is a string (like 'something').
I've never seen this notation in APIs before and I know I could do something like:
var array = Object.id.split(':');
return array[array.length - 1];
...but it feels wrong and I'm thinking there is a standard behind this or a best practice I'm missing?
The way you are doing it is correct, although it could be simplified:
return Object.id.split(":").pop();
Since as shown in the documentation for Array.prototype.pop, it returns the element popped from the array (the last element).
One suggestion with your code - don't use the name Object because that's reserved in JavaScript - use something else (object would be fine since JS variable names are case-sensitive).

Use string variable to access value of object

I have a text input.
I want the user to be able to fill out a value in that text input like some of these examples:
results[0].address_components[0].long_name
results[0].formatted_address
fo.o[0].bar (where fo.o is a single key)
etc. (pretty much literally anything)
Then I want to take that value and use it as a key on some parsed JSON. So like...
$.parseJSON('data.json').results[0].address_components[0].long_name would return something like San Francisco.
How can I do this?
If I save the input value as a variable, say selector, and then try $.parseJSON('data.json')[selector] it just comes back undefined.
If I try to regex the selector and convert all instances of [ into . and remove all ] and split at . then reduce, then selectors like fo.o (one key) will break...
Thanks in advance!
You should generally set the results of parseJSON to a variable, rather than parse it every time you access it. parseJSON is generally going to go down to C code (depending on the environment), but it will still be really inefficient to call it over and over.
var res = $.parseJSON('data.json');
From there, you can access it like you would any other JavaScript object:
res.results, which is identical to res["results"] (which, in your case appears to be some kind of array).
A string key with special characters (., -, and pretty much anything non a-zA-Z0-9) is always accessed via the second form: res["fo.o"].
Note that this chains, so you can access res["fo.o"]["bar"] exactly as you'd address res["fo.o"].bar.
I would recommend using a JavaScript library like lodash for this (if this is feasible in your project, otherwise looking at its implementation might help):
It provides a large set of utility functions. The get function does exactly what you are looking for, namely it resolves a path on an object.
Sample code (assuming _ is your lodash reference):
var path = 'results[0].address_components[0].long_name'; // the user input
var data = $.parse('data.json');
var result = _.get(data, path); // resolves the path on the data object
As for the fo.o property name, I doubt there would be an easy solution, as this essentially makes your syntax ambiguous. How would you distinguish between a property fo.o and fo?
use eval. You would put everything as a string. So just concatenate strings based on the input. Then eval it. for example:
var str = "$.parseJSON('data.json').results[0].address_components[0].long_name";
and then eval it at runtime.
var result = eval(str);

Javascript function that converts unicode notation code to utf-8 in HTML

I follow the link How to convert javascript unicode notation code to utf-8? to run the function in my console.
function encode_utf8( s ){return unescape( encodeURIComponent( s ) );}( '\u4e0a\u6d77' )
Then I get:
"上海"
However, when I do this way:
foo = function(s){return unescape( encodeURIComponent( s ) );}
foo('\u4e0a\u6d77');
foo("\u4e0a\u6d77");
Then I get"ä¸æµ·" "ä¸æµ·"
What is wrong with the function? Thanks ahead.
EDIT:
I thank you guys' explanation. Now I find that you just need to directly input in Chrome console '\u4e0a\u6d77', then I will get "上海".
However my original problem is that I want to convert unicode code to utf-8 in the html file, not in console. I could not find the answer.
EDIT:
Again, I want to thank you guys.
Now I find that my problem is that I get string like '\\u4e0a\\u6d77' from txt file. (Note here there are two back slashes). How can I change it to '\u4e0a\u6d77' (I want to get rid of one back slash).
Now I know once you get '\u4e0a\u6d77' (only one back slash) and then HTML will automatically show it as "上海"
EDIT:
Now I find the solution: HERE
Your first one is a function declaration followed by an unrelated expression in parentheses containing a string literals. The function is never called. The end result of that in the console is the value of the expression within the parens, which is the value of the string '\u4e0a\u6d77', which is of course "上海".
Your second one first creates the function (via a function expression), then calls it (twice, for some reason), passing in that string, and shows the function's return value.
So you see a difference because in the first case, you never call the function, you just get back the same string you provided. In the second case, you actually call the function and get back the UTF-8 data.

Passing an array as the code to eval in setTimeout?

Today my friends sent my some code that did something unexpected:
setTimeout(["console.log(1", "2)"], 1000)
I expected this to fail or do some magic, but it just prints 1 2 after 1 second.
I can see it possibly evaluating the array to "console.log(1,2)" using a simple array.join(','), but why does that happen?
I've looked into the eval capabilities of setTimeout, but it should only do a function or a string. The use of an array here doesn't make any sense, and searching Google for why this does work turns up nothing, or even close use cases.
setTimeout can evaluate a string as javascript, if the value is not a function it will then convert the value to a string, probably by using toString()
You can see if you do this
"" + ["console.log(1", "2)"]
or
["console.log(1", "2)"].toString();
you get
'console.log(1,2)'
Then it get's evaluated accordingly
If it is not a function then it uses .toString() to get a string value.

Writing my own split method

I found out earlier today that split() doesn't work if attached to a single value.
I would like to write my own split() method so that if I sent it a single value, it creates an array with a single value.
Q: Should I change the split prototype or write a function?
var SPLIT=function(X) {
return X.toString().split()
}
To clarify, split() does work with a "single value". The problem in your last question was that the value returned was not a string, and hence the .toString() is necessary.
In my opinion, there's no need to write another function for this. Simply remember to convert your values to a string before calling .split() on it.
If you must have a function that does this, then to answer your question, create a new function and don't modify the prototype. While it may seem harmless to modify the prototype of Number or Object in this case, it's generally considered bad practice as other code (e.g. libraries you're using) may not be expecting it.

Categories