Javascript: eval behavior in IE8 - javascript

Please consider the example at http://jsfiddle.net/KE8Mv/
HTML
<input type='text' id="log" />
JavaScript
var f = function(){
if(console && console.log)
console.log('hello eval issue!');
}.toString();
var f1 = eval('('+f+')');
var logMsg = f1===undefined?'eval returns none':'eval returns function';
$('#log').val(logMsg);
The eval invoke returns function() object in FF and Chrome, but returns undefined in IE8:(
What might be the issue? How to get the same behavior in all the browsers?

If you really want to do it like this, you can create an anonymous function that will return you the function you need:
var f1 = eval("(function() {return " + f + ";})()");
Edit: Or even simpler (it is only necessary to make the browser consider this an expression with the function being the result of that expression, so we can use the comma operator):
var f1 = eval("0, " + f);
But you might want to consider using the Function constructor that takes the function body as a string.

Related

combining function declaration and expression doesn't work [duplicate]

The code goes like this (The syntax may seem odd but as far as I know, there is nothing wrong with it. Or is there?)
var add=function addNums(a, b) {
return a+b;
}
alert("add: "+ add(2,3)); // produces 5
alert("addNums: "+addNums(2,3)); // should also produce 5
addNums() is declared as a function. So, when I pass the parameters to it, it should also return the result.
Then, why am I not getting the second alert box?
You are seeing a named function expression (NFE).
An anonymous function expression is where you assign a function without a name to a variable1:
var add = function () {
console.log("I have no own name.");
}
A named function expression is where you assign a named function to a variable (surprise!):
var add = function addNums() {
console.log("My name is addNums, but only I will know.");
}
The function's name is only available within the function itself. This enables you to use recursion without necessarily knowing the "outside name" of the function - even without having to set one in the first place (think callback functions).
The name you choose shadows an existing name, so if another addNums is defined elsewhere it will not be overridden. This means you can use any name you like without fear for scoping problems or breaking anything.
In the past you would have used arguments.callee to refer to a function inside itself without knowing its name. But support for that is being removed from JavaScript2, so NFEs are the correct way to do this nowadays.
Here is a lot of stuff to read on the topic: http://kangax.github.io/nfe/
1 Assigning it to a variable is not necessary, it just serves as an example to distinguish it from a plain function declaration. It could be any other context where JS expects an expression (a function argument, for example).
2 You will receive an error if you have strict mode in effect and try to use arguments.callee.
The problem
You are using a named function expression - and a function expression's name is not available outside of that function's scope:
// Function statement
function statement() {
console.log("statement is a type of " + typeof statement);
}
statement();
console.log("statement is a type of " + typeof statement);
results in:
statement is a type of function
statement is a type of function
whereas:
// Function expression with a name
var expression = function namedExpression() {
console.log("namedExpression is a type of " + typeof namedExpression);
};
expression();
// namedExpression(); // uncommenting this will cause an exception
console.log("expression is a type of " + typeof expression);
console.log("namedExpression is a type of " + typeof namedExpression);
will produce:
namedExpression is a type of function
expression is a type of function
namedExpression is a type of undefined
The solution
Depending on what you are trying to do, you want do do one of the following:
Change your function declaration to use a statement and then alias your function:
function addNums(a, b) {
return a + b;
}
var add = addNums;
Alias both names to your expression:
var add = addNums = function addNums(a, b) {
return a + b;
};
Why does JavaScript do things this way?
Named function expressions are useful because they let you reference a function inside itself and they give you a name to look at in a debugger. However, when you use a function as a value you don't generally want parts of it leaking into the enclosing scope. Consider:
(function setup() {
var config = retrieveInPageConfig();
if (config.someSetting) {
performSomeOtherSetup();
}
kickOffApplication();
})();
This is a perfectly licit use of a function expression - in such a case you would not expect the name setup to leak into the enclosing scope. Assigning a named function expression to a variable is just a special case of this, that just happens to look like a function statement declaration.
addNums is only available in the scope of the newly-defined function.
Quite obviously, when a function expression has a name (technically —
Identifier), it is called a named function expression. What you’ve
seen in the very first example — var bar = function foo(){}; — was
exactly that — a named function expression with foo being a function
name. An important detail to remember is that this name is only
available in the scope of a newly-defined function; specs mandate that
an identifier should not be available to an enclosing scope.
Read more detail form this article.
You should either declare as named function:
function addNums(){
}
or assign function to the variable:
var add= function(){// your code }
The reason why addNum() doesn't return anything is because it's not added to the global scope with the way you declare it.
Demo
function addNums(a, b) {
return a+b;
}
var add = addNums;
alert("add: "+ add(2,3));
alert("addNums: "+addNums(2,3));
I have added your code in my test web app and works fine for me. Here is the code. Would you please share the more details of your code/app?
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="JavascriptTest.aspx.cs" Inherits="GetGridViewColumnValue.JavascriptTest" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script type="text/javascript">
var add = function addNums(a, b) {
return a + b;
}
alert("add: " + add(2, 3)); // produces 5
alert("addNums: " + addNums(2, 3));
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
</form>
</body>
</html>
Cheers!!!
Consider the following code:
var f = function g() {
// function
};
The g will be access only in the function itself, and its needed when you want to use the function
by itself, for writing recursive functions. For example, you want the factorial function:
var f = function factorial(x) {
if (x <= 1) return 1;
// here we want to use the function itself
return x * factorial(x - 1);
};
console.log(f(5));
However, its really needed as you can access the function itself by arguments.callee:
// note that the function has not any name
var f = function (x) {
if (x <= 1) return 1;
// here we want to use the function itself
return x * arguments.callee(x - 1);
};
console.log(f(5));
I've slightly modified your code:
var add = function addNums(a, b){
return a+b;
}
console.log(add);
console.log(typeof(add));
console.log("add: "+ add(2,3)); // produces 5
console.log("addNums: "+addNums(2,3));
And then proceeded to run it inside of node.js to get this output:
[Function: addNums]
function
add: 5
/home/mel/l.js:44
console.log("addNums: "+addNums(2,3));
^
ReferenceError: addNums is not defined (... backtrace)
Normally, a variable assigned an inline anonymous method would print out [Function] when called with console.log(var); Here console.log(add); results in the name of the function also being printed.
So it's not like your addNums declaration is invalid or not used, it's simply scoped to be bound to the variable add.
addNums is not a function in the global namespace..
It's an function defined only within the assignment operator..
if you want to have access to it try the follow:
function addNums(a, b)
{
return a+b;
}
var add = addNums;
var add = function <---- the function name is add and it's value is a function..

How to force 'function' to be an expression, not a statement?

While this code is fine:
var x = function() { };
This code is not:
function() { };
The top example creates an anonymous function and assigns it to x. The bottom example is a statement, where a function name is required, so it is a syntax error.
Now, it may seem pointless to define an anonymous function and not assign it anywhere, but here's an example that confronts the behavior:
var x = eval('function() { }');
Which should behave just like the first example, but is a syntax error.
Deep in the app I'm working on, we come to this issue. I want function() { } to be an expression.
A short explanation why is that this is a native OSX app calling javascript into a WebView. We have an evaluateJavascript function which the native layer can use to call arbitrary javascript. evaluateJavascript wraps the given code with try/catch for error-handling, because it's the only way to get detailed error information. So if you call myCallback = evaluateJavascript("function() { }"), we generate a function with the following body:
try {
return eval('function() { }');
} catch(e) {
// ....
}
And return the result.
When possible, don't use eval. Another option to find errors is if you listen for errors on the window (or equivalent) object and import the scripts as <script>s which are added and removed immediately.
Doing anything on the same line before function will cause function to be an expression
All of the following are valid (although useless)
0, function () {};
(function() {});
+function () {};
-function () {};
!function () {};
// etc
Function expressions like this are usually done for IIFEs, i.e.
(function (foo) {
console.log(foo);
}('bar'));
// "bar" logged
But you can apply the style to your eval-ing. Either parenthesis or the comma operator should work for you
var code = 'function () {}';
var foo = eval('0, ' + code);
foo; // function () {}
Can't you do
x = eval('y = function() {}')
?
You say var x = eval('function() { }'); should behave just like the first example. Why do you think so? Your eval argument
function() { }
is a statement and invalid as you point out above. You could make it an expression like this:
var x = eval('(function() { })');
Attempt/Approach- 1 : Below should work
var scope = {};
eval('scope.x = function() { return "Hello World"; }');
console.log(scope.x());
Output
Hello World
[Finished in 0.3s]
** Approach - 2 **
After reading link on IIFE insuggested in comments of above question, I tried below - and it seems to work as well.
var x = eval('(function() { return "Hello World"; })');
console.log(x());
However, I realized that with IIFE, we need to have code like (function(){})() - note that trailing (). However, in the Approach-2 code - I did not have the trailing (). Then, I looked up the eval documentation, and from it I came to know the following (which explains why Approach-2 works):
eval as a string defining function requires "(" and ")" as prefix and
suffix

eval returning variable name instead of undefined. (javascript)

Update
The code for the function / class is stored in a string which is why I cannot call it directly. The idea is to do introspection on the object and enumerate its data members which works when it is a function but doesn't work when a variable like the one below is eval'ed.
I am trying to evaluate an object in javascript. Something like this.
var myObj {
greet: "Greeting",
myPrint: function() {
alert("hello");
}
};
The idea is to be able to run this in eval and get the variable name somehow (myObj) or an object created. I have experimented with various methods using eval but cannot figure this out. This works when I have something like this.
function myObj() {
this.greet = "Greeting";
this.myPrint = function() {
alert("hello");
}
};
Running eval("(" + code + ")"); where code is a string containing the above function returns myObj() to me.
Update 2
So basically I want to evaluate something like this.
eval("var x = 5"); and I am trying to get x. Since its a string being evaluated, even though it gets added to the window namespace, there is no way to decipher it apart from parsing the string. Now this is just a simple example but as I said, it's a little difficult with the 1st piece of code. As I said...
eval("function test() { return 'hello'; }"); return test() which is similar to what I am expecting for the "var x = 5" statement.
Is there a way to do this similarly for the 1st case which I am missing ?
Thanks
A code:
var sCode = '{ great: "Greating", myPrint: function() { alert("hello!"); } }',
oObj = eval("(" + sCode + ")");
oObj.myPrint(); // alert "hello"
console.log(oObj.great); // prints "Greating"
Are you trying to dynamically call a callback?
var myObj = { // fixed this line of code as it was missing the =
greet: "Greeting", // replaced ; with ,
myPrint: function() {
alert("hello");
}
};
console.log(eval(myObj)); // returns obj as expected.
If I am correct in my assumption you would need to use bracket notation and EVAL is not needed
So if you were passing a String it would look like:
var str = 'myPrint';
var strTwo = 'greet'
myObj[str](); // to execute the function
myObj[strTwo]; // now contains "Greeting"
Which would execute that function.
Hope that helps!
Tim
EDIT:
var myObj = 'var myObj = { greet: "Greeting", myPrint: function() { alert("hello"); } }'
console.log(eval(myObj));
myObj.myPrint();
Then this is what you want if this does not work it means you are not escaping your string correctly:
http://jsfiddle.net/XtyHh/
You eval the object without executing the myPrint function.
You would need to do something like
myObj.myPrint()
To get it to throw the alert.
[edit] To immediately run the myPrint function change your code to this:
var myObj = {
greet: "Greeting",
myPrint: (function() {
alert("hello");
})();
};

Given a string describing a Javascript function, convert it to a Javascript function

Say I've got a Javascript string like the following
var fnStr = "function(){blah1;blah2;blah3; }" ;
(This may be from an expression the user has typed in, duly sanitized, or it may be the result of some symbolic computation. It really doesn't matter).
I want to define fn as if the following line was in my code:
var fn = function(){blah1;blah2;blah3; } ;
How do I do that?
The best I've come up with is the following:
var fn = eval("var f = function(){ return "+fnStr+";}; f() ;") ;
This seems to do the trick, even though it uses the dreaded eval(), and uses a slightly convoluted argument. Can I do better? I.e. either not use eval(), or supply it with a simpler argument?
There's also the Function object.
var adder = new Function("a", "b", "return a + b");
You can do this:
//in your case: eval("var fn = " + fnStr);
eval("var fn = function(){ blah1;blah2;blah3; }");
fn();
Not sure how to get it much simpler, sometimes there's no (better) way around eval(). Here's a quick example of this in action.
Use parentheses.
var fn = eval("(function() {...})");
This technique is also good for transmitting JSON values.
By the way, it's often better to build functions by composing them directly from other functions. If you are using strings, you have to worry about things like unexpected variable capture.
Here's what I use for simple cases:
// an example function
function plus(...args) {
return args.reduce( (s,v) => s+v, 0 );
}
// function to string
let str = plus.toString();
// string to function
let copy = new Function('return ' + str)();
// tests
console.assert(plus.name == 'plus');
console.assert(copy.name == 'plus');
console.assert(plus.constructor == Function);
console.assert(copy.constructor == Function);
console.assert(plus(1,2,3,4) === copy(1,2,3,4));
console.assert(plus.toString() === copy.toString());
You can also insert the string into a script element and then insert the script element into the page.
script_ele = window.document.createElement("script");
script_ele.innerHTML = 'function my_function(){alert("hi!");}';
window.document.body.appendChild(script_ele);
my_function();
One way:
var a = 'function f(){ alert(111); } function d(){ alert(222);}';
eval(a);
d();
A second more secure way to convert string to a function:
// function name and parameters to pass
var fnstring = "runMe";
var fnparams = ["aaa", "bbbb", "ccc"];
// find object
var fn = window[fnstring];
// is object a function?
if (typeof fn === "function") fn.apply(null, fnparams);
function runMe(a,b){
alert(b);
}
Look at the working code: http://plnkr.co/edit/OiQAVd9DMV2PfK0NG9vk
The Function constructor creates a new Function object. In JavaScript every function is actually a Function object.
// Create a function that takes two arguments and returns the sum of those arguments
var fun = new Function("a", "b", "return a + b");
// Call the function
fun(2, 6);
Output: 8
You can call Parse your string as javascript fuction
function getDate(){alert('done')} // suppose this is your defined function
to call above function getDate() is this in string format like 'getDate()'
var callFunc=new Function('getDate()') //Parse and register your function
callFunc() // Call the function

How to turn a String into a JavaScript function call? [duplicate]

This question already has answers here:
How to execute a JavaScript function when I have its name as a string
(36 answers)
Closed 9 years ago.
I got a string like:
settings.functionName + '(' + t.parentNode.id + ')';
that I want to translate into a function call like so:
clickedOnItem(IdofParent);
This of course will have to be done in JavaScript. When I do an alert on settings.functionName + '(' + t.parentNode.id + ')'; it seems to get everything correct. I just need to call the function that it would translate into.
Legend:
settings.functionName = clickedOnItem
t.parentNode.id = IdofParent
Seeing as I hate eval, and I am not alone:
var fn = window[settings.functionName];
if(typeof fn === 'function') {
fn(t.parentNode.id);
}
Edit: In reply to #Mahan's comment:
In this particular case, settings.functionName would be "clickedOnItem". This would, at runtime translate var fn = window[settings.functionName]; into var fn = window["clickedOnItem"], which would obtain a reference to function clickedOnItem (nodeId) {}. Once we have a reference to a function inside a variable, we can call this function by "calling the variable", i.e. fn(t.parentNode.id), which equals clickedOnItem(t.parentNode.id), which was what the OP wanted.
More full example:
/* Somewhere: */
window.settings = {
/* [..] Other settings */
functionName: 'clickedOnItem'
/* , [..] More settings */
};
/* Later */
function clickedOnItem (nodeId) {
/* Some cool event handling code here */
}
/* Even later */
var fn = window[settings.functionName];
/* note that settings.functionName could also be written
as window.settings.functionName. In this case, we use the fact that window
is the implied scope of global variables. */
if(typeof fn === 'function') {
fn(t.parentNode.id);
}
window[settings.functionName](t.parentNode.id);
No need for an eval()
Here is a more generic way to do the same, while supporting scopes :
// Get function from string, with or without scopes (by Nicolas Gauthier)
window.getFunctionFromString = function(string)
{
var scope = window;
var scopeSplit = string.split('.');
for (i = 0; i < scopeSplit.length - 1; i++)
{
scope = scope[scopeSplit[i]];
if (scope == undefined) return;
}
return scope[scopeSplit[scopeSplit.length - 1]];
}
Hope it can help some people out.
JavaScript has an eval function that evaluates a string and executes it as code:
eval(settings.functionName + '(' + t.parentNode.id + ')');
eval() is the function you need to do that, but I'd advise trying one of these things to minimize the use of eval. Hopefully one of them will make sense to you.
Store the function
Store the function as a function, not as a string, and use it as a function later. Where you actually store the function is up to you.
var funcForLater = clickedOnItem;
// later is now
funcForLater(t.parentNode.id);
or
someObject.funcForLater = clickedOnItem;
// later is now
(someObject.funcForLater)(t.parentNode.id);
Store function name
Even if you have to store the function name as a string, you can minimize complexity by doing
(eval(settings.functionName))(t.parentNode.id);
which minimizes the amount of Javascript you have to construct and eval.
Dictionary of handlers
Put all of the action functions you might need into an object, and call them dictionary-style using the string.
// global
itemActions = { click: clickedOnItem, rightClick: rightClickedOnItem /* etc */ };
// Later...
var actionName = "click"; // Or wherever you got the action name
var actionToDo = itemActions[actionName];
actionToDo(t.parentNode.id);
(Minor note: If instead here you used syntax itemActions[actionName](t.parentNode.id); then the function would be called as a method of itemActions.)
While I like the first answer and I hate eval, I'd like to add that there's another way (similar to eval) so if you can go around it and not use it, you better do. But in some cases you may want to call some javascript code before or after some ajax call and if you have this code in a custom attribute instead of ajax you could use this:
var executeBefore = $(el).attr("data-execute-before-ajax");
if (executeBefore != "") {
var fn = new Function(executeBefore);
fn();
}
Or eventually store this in a function cache if you may need to call it multiple times.
Again - don't use eval or this method if you have another way to do that.
I wanted to be able to take a function name as a string, call it, AND pass an argument to the function. I couldn't get the selected answer for this question to do that, but this answer explained it exactly, and here is a short demo.
function test_function(argument) {
alert('This function ' + argument);
}
functionName = 'test_function';
window[functionName]('works!');
This also works with multiple arguments.
If settings.functionName is already a function, you could do this:
settings.functionName(t.parentNode.id);
Otherwise this should also work if settings.functionName is just the name of the function:
if (typeof window[settings.functionName] == "function") {
window[settings.functionName](t.parentNode.id);
}
This took me a while to figure out, as the conventional window['someFunctionName']() did not work for me at first. The names of my functions were being pulled as an AJAX response from a database. Also, for whatever reason, my functions were declared outside of the scope of the window, so in order to fix this I had to rewrite the functions I was calling from
function someFunctionName() {}
to
window.someFunctionName = function() {}
and from there I could call window['someFunctionName']() with ease. I hope this helps someone!
I prefer to use something like this:
window.callbackClass['newFunctionName'] = function(data) { console.log(data) };
...
window.callbackClass['newFunctionName'](data);
Based on Nicolas Gauthier answer:
var strng = 'someobj.someCallback';
var data = 'someData';
var func = window;
var funcSplit = strng.split('.');
for(i = 0;i < funcSplit.length;i++){
//We maybe can check typeof and break the bucle if typeof != function
func = func[funcSplit[i]];
}
func(data);
In javascript that uses the CommonJS spec, like node.js for instance you can do what I show below. Which is pretty handy for accessing a variable by a string even if its not defined on the window object. If there is a class named MyClass, defined within a CommonJS module named MyClass.js
// MyClass.js
var MyClass = function() {
// I do stuff in here. Probably return an object
return {
foo: "bar"
}
}
module.exports = MyClass;
You can then do this nice bit o witchcraft from another file called MyOtherFile.js
// MyOtherFile.js
var myString = "MyClass";
var MyClass = require('./' + myString);
var obj = new MyClass();
console.log(obj.foo); // returns "bar"
One more reason why CommonJS is such a pleasure.
eval("javascript code");
it is extensively used when dealing with JSON.

Categories