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.
Related
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.
So I'm trying to make a function that will have a random name generated on page load, but I'm having problems calling the method later.
This is what I got so far:
var methodName = Math.floor(Math.random()*1000001);
window[methodName] = function(){
alert("It works!");
}
window.onload = function start() {
methodName();
}
But I'm having problems calling it, since methodName(); would actually be a random number. So how could I call the methodName() function?
You can reference the property the same way that you set it:
window[methodName]();
If you're trying to make a function that can't be found by code loaded later in the page for security reasons, you should know that properties are of window are enumerable by default, and JavaScript's PRNG is not crypto-strong.
#MikeSamuel that's exactly what I'm trying to do.
If you had a crypto-strong source of randomness then you can use a lock&key approach to make a function that can only be called by someone who knows the secret.
For example,
(function () {
// Multiple calls to a secure source of randomness could get you more entropy than 64B.
var key = Math.random() + '/' + Math.random() + '/' + Math.random();
var sensitiveFunction = function () { alert("Don't leak me"); }
var slice = [].slice;
function lock(f) {
var g = f;
f = null; // arguments is widgy and leaky in non-strict mode.
return function (unlocker, var_args) {
if (key !== unlocker) { throw new Error(); }
return g.call(this, slice.apply(arguments, 1));
};
}
myGlobal = lock(sensitiveFunction);
})();
which uses the secret to wrap a function in one whose toString() does not return sensitive code, and which will only be callable by code that can read var key.
Is Math.random() cryptographically secure? discusses some alternatives to Math.random for strong nonces in JavaScript but I don't have personal experience with any of them.
This isn't practically useful unless you can get key out of this closure to code that needs it, so you need to have a secure communication channel to that code. You probably also want to have any script that defines this go through <script> elements and delete their text content from the DOM so that the body of the sensitive function can't be read that way.
I believe some frameworks like waterken use the URL fragment to seed web applications with secrets and then use techniques like this within the page to keep them from prying code.
Note that making properties with unpredictable names un-enumerable does not protect them.
In EcmaScript 5, getOwnPropertyNames does not respect enumerability. The only standardized way to get truly un-enumerable properties is with weak maps and a closely held object token and that will have to wait for EcmaScript 6 to be in an actual spec though browser vendors are implementing a lot of ES6 speculatively.
I want to know if it's possible to do something like:
var f = function;
and than use f like it would be the js function keyword
if something like this would be possible I would use it for js code minimization, cuz I have a lot of function in my code
Similar to what Pointy pointed out in the comments, what you can do is use the function constructor to create a new function and pass it as string. In other words:
function f(s) { return new Function(s) };
var foo = f('var s = "hello"; return s');
alert(foo()); //=> "hello"
But again, I think this is unnecessary.
Edit: To add parameters you'd use the arguments object.
function f() {
var args = Array.prototype.slice.call(arguments);
var func = args.pop();
return new Function(args.join(','), func);
}
var add = f('a,b', 'return a + b');
It is not possible to do as you describe.
The closest I can think of is to make a function for generating functions, using eval to parse a passed string. Using eval however, is generally evil and should be avoided. Overall, I would not recommend doing something like this at all.
Also, it is worth noting that there is very little point in doing what you want, as javascript sent over the wire should be compressed first, so the the word function will be represented by one token, regardless of how long the word is.
If you want your source code to be more readable and concise, I would recommend coffee-script which compiles to javascript, and allows you to define functions without using even the first letter of function. Chuck Norris would approve!
Summary of conclusions and recommendations
use coffee-script for cruft free source
compile it to verbose javascript you never look at
minify that javascript (uglify is a great compressor, or google's closure)
gzip it (will compress repetitive strings well)
send it
The key issue here is that after it is gzipped, the size of the word function becomes irrelevant, so the only remaining issue is the readability of your source code.
Yeah...to be quite honest, I wouldn't worry about trying to shorten the function keyword to 'f' which gives you back very little for the work and it would also hurt the readability of your code. And, unless you have something like a million functions, I wouldn't focus on that. As #prodigitalson said - run it through a minifier. That should take care of the real minifications that are possible in your code and still maintain readability in your code base (which is more important than saving a few bytes).
Also, per my comment, there is something (potentially) on its way to replace the long 'function' keyword (something Brendan Eich has said he would have considered changing - you have to remember that he designed the language in 10 days or so). Read more about it here: Fat Arrow Syntax Of course, these sorts of things can always change...but the standards definition bodies are looking at it.
You could do this with the hygenic macro functionality of http://sweetjs.org/
Is it safe to rely on Function.prototype.toString to return a string that will parse as a valid javascript function (for user-defined functions)?
Are there any commonly-used javascript engines that deviate from the norm as far as how they represent function objects in string form?
I have seen this question, but I'm not sure if it's asking the same thing. I don't care if the formatting is exactly the same in all implementations or whatever, I'm more worried about some minified js engine just stripping out the whole function body...
Another related question, but not closely related enough to have a satisfying answer for this question.
I think it's safe since it's a standard. Every serious engine would do. That's also what my project Jscex is based on. It works for all the browsers (even the legacy IE6) and Node.js. I do this kind of things for year. :)
It should be noted that eval'd code will take on the current scope and the Function constructor will only take on the global scope.
function createClosure() {
var x = 20,
y = 10;
// Doesn't know what x & y are
var fn = new Function("return x + y");
// Evaluates normally
var result = eval("x + y");
}
Let's have a function call
function doSomethingAndInvokeCallback(callback){
// do something
callback();
}
I can check if given argument is function if(typeof callback == 'function')
How can I discover, if given callback function is function and isn't empty?
like
doSomethingAndInvokeCallback(function(){
//nothing here
})
There is no totally reliable way to know if a function is empty because there are multiple kinds of functions in JS, some implemented with JS and some implemented with native code and you can't know for sure whether the function passed in does anything or not. If you want to limit the passed in function to only very simple JS functions, you could use the mechanisms outlined by other answers here (examining the source of the function). But, I would not recommend doing that in anything but a tightly controlled situation because there are lots of legal javascript ways to break that.
I would suggest that you should change the contract of your function arguments and have the caller pass null or not pass anything (which will make the argument undefined) rather than an empty function. Then, it will be very clear whether they intend to have a function called or not. If they then pass an empty function instead of null or undefined, they are getting the behavior that the interface of the function specifies. The caller can choose the desired behavior and you can implement your function in a more failsafe manner.
Also, one of your main suppositions in your question is not quite right. You cannot safely use typeof x == "function" to determine if something is a function as that will not work reliably in some older versions of IE for some types of functions. If you want to learn how to detect if something is a function at all, you can learn from jQuery here (even if you're not using it). jQuery has a function it uses internally all the time called jQuery.isFunction() that returns a bool. It uses that mostly for testing arguments to see if a function was passed.
Internally, it calls:
Object.prototype.toString.call(o)
and then examines the result. If the result has "Function" in it, then test test parameter is a function.
So, using the same technique used in jQuery, you could build your own simple little isFunction routine like this:
function isFunction(test) {
return(Object.prototype.toString.call(test).indexOf("Function") > -1);
}
Of course, if you have jQuery available, you could just use it's own version:
jQuery.isFunction(o)
When there are questions with potential cross browser compatibility issues, I find it instructional to look at how one of the big libraries solves the issue, even if you aren't going to be using that library. You can be sure that the libraries have been vetted against many browsers so a technique they are using is safe. You sometimes have to unwrap all their own internal routines they may use to figure out what they're really doing (which was the case for this function), but you can save yourself a lot of legwork.
You can see a working test bed for this here: http://jsfiddle.net/jfriend00/PKcsM/
In modern browsers typeof fn === "function", but in older versions of IE, some functions give a typeof === "object" which is probably why jQuery uses this other method which does work in those older versions of IE.
It seems that you can define a function to retrieve the body of a function(1). I wrote a small (non-definitive) test of this:
http://jsfiddle.net/6qn5P/
Function.prototype.getBody =
function() {
// Get content between first { and last }
var m = this.toString().match(/\{([\s\S]*)\}/m)[1];
// Strip comments
return m.replace(/^\s*\/\/.*$/mg,'');
};
function foo() {
var a = 1, b = "bar";
alert(b + a);
return null;
}
console.log(foo.getBody());
console.log(foo.getBody().length);
One possibility is matching the .toString result against a regexp to get the function body, and then trim to check whether it has become an empty string:
var f = function foo() {
};
/^function [^(]*\(\)[ ]*{(.*)}$/.exec(
f.toString().replace(/\n/g, "")
)[1].trim() === ""; // true
That ugly regexp does take care of spaces aroung named functions as well as extraneous spaces before the name and the opening brace. Spaces like in foo () do seem to be removed, so there is no reason to check for those.
You might be able to get this from .toString():
var blank = function(){};
var f = function(){};
var f2 = function() { return 1; };
f.toString() == blank.toString(); // true
f2.toString() == blank.toString(); // false
but this is really prone to error:
var blank = function(){};
var f = function(){ }; // extra space!
f.toString() == blank.toString(); // false
You could munge the strings a bit to try to overcome this, but I suspect this is very browser-dependent. I wouldn't actually try to do this in a production environment if I were you. Even if you normalize the whitespace, it still won't catch other no-op lines, including comments, useless var statements, etc. To actually address these issues, you'd probably need a whole tokenizer system (or a crazy regex).
You can't do it for a host function, but for others, you can fairly reliably do
function isEmpty(f) {
return typeof f === "function" &&
/^function[^{]*[{]\s*[}]\s*$/.test(
Function.prototype.toString.call(f));
}
This isn't efficient, but major interpreters implement toString for functions in such a way that it works, though it will not work on some interpreters for some empty-ish functions
function () { /* nothing here */ }
function () { ; }
function () { return; }
In some implementation you can just do a toString() on the function and get it's content. Though it contains comments etcetera.
var foo = function(){ /* Comment */ };
alert(foo.toString());