btevfik
btevfik

Reputation: 3431

Passing a function expression into new Function() with a variable

This is the most confusing thing ever. The title probably doesn't make much sense. I did my best. Hope I can be clear. Ok i am looking at the tic-tac-toe example from google channel api.

in the javascript portion.

they have something like this;

sendMessage = function(param) {
  alert(param);
  //this part actually sends message to server, 
  //for simplicity lets assume it pops up alert.    
  }

init = function(){
  var input = 3;
  var submitButton = document.getElementById('submitButton');
  submitButton.onclick = new Function('sendMessage(' + input + ')');
}

setTimeout(init, 100);

this pops up an alert and prints 3. I am not sure how this works. But it works. If one can explain that, that would be great too. I could not find anywhere else use of new Function() like this.

The problem is, if the input is a string,

var input = "test";

this does not work, and there is no alert that pops up.

thanks for any explanation and help.

Upvotes: 0

Views: 698

Answers (3)

John Dvorak
John Dvorak

Reputation: 27287

The Function constructor works by evaluating its argument as a function body.

... = new Function('sendMessage(' + input + ')');

is similar to

... = eval("function(){sendMessage("+input+")}";

For numeric inputs, this works, since their textual representation works as a numeric literal. For textual inputs, it doesn't. A limited support can be gained by doing

... = new Function('sendMessage("'+input+'")');

A more general way would be to use

... = new Function('sendMessage("'+JSON.stringify(input)+'")');

However, I recommend using an immediately invoked function expression (IIFE) instead to avoid any form of eval and the dependence on the JSON object, which does not exist in very old browsers (IE<8):

... = (function(input){
  return function(){
    sendMessage(input)
  }
})(input)

Or, if the input variable doesn't change, you don't need to capture its value:

... = function(){ sendMessage(input) }

Or, if you don't use this inside sendMessage, you can use bind (IE8 needs shimming):

... = sendMessage.bind(undefined, input)

Upvotes: 1

loxxy
loxxy

Reputation: 13151

When the input is a string, the function call becomes :

sendMessage(string)

which should actually be :

sendMessage("string") or sendMessage('string')

sendMessage = function(param) {
  alert(param);   
  }

init = function(){
  var input = '"string"';
  var submitButton = document.getElementById('submitButton');
  submitButton.onclick = new Function('sendMessage(' + input + ')');
}

setTimeout(init, 100);

Here is fiddle to see how you could use.

Upvotes: 0

Keith A
Keith A

Reputation: 801

the parameter to function gets evaluated.. that is to say it is executed. that's why it works.

when you pass a string it didnt work simply because that string you pass will be treated as an object or a variable instead of a string.. and we all know it doesnt exist.

i.e

this works:

submitButton.onclick = new Function('sendMessage(3)');

this does not:

submitButton.onclick = new Function('sendMessage(test)'); //because test does not exist

but this will

submitButton.onclick = new Function('sendMessage("test")');

so if you change your code to:

submitButton.onclick = new Function('sendMessage("' + input + '")');

then all is well

Upvotes: 0

Related Questions