How to hook jQuery own functions, to check if a string can be eval'ed to a function?
I want to be able to do this
$('.class').bind({'click':'function(){ ... }'}); // note that the value is a string
and somehow, checking inside a hooked "bind", that it's indeed a function, and eval()
or new Function
the string, so it will be correctly assigned as an event.
The reason I want to do this is because JSON doesn't allow functions to be defined as values, only strings/ints. I would want to find a way to apply this for all jquery functions (like animate(), click(), live(), etc) that take a handler/function as parameter. it would be a huge hassle and I think, and would become impractical after each new version of jQuery released
Or is there any better way to accomplish t开发者_JAVA技巧his? checking for the first 8 characters if they are === 'function' and then eval it is not a good idea, since it can be a "legitimate" text string. I tried passing a function as a result from a ajax JSON response, but $.parseJSON failed silently.
Is this what you are looking for, http://jsbin.com/adewe4/3
function definition https://gist.github.com/862112
You can use the parseJSONwithFunctions
method to parse the JSON data that you receive as the AJAX response using $.getJSON
.
parseJSONwithFunctions
converts the function body as strings in the JSON into actual function objects; so rather than trying to make jQuery eval strings, you can just pass the function reference to it.
If you use the method as,
var my_json_data = {};
$.getJSON('URL_TO_GET_JSON', function (data) {
my_json_data = parseJSONwithFunctions(data);
});
and the you can define handlers as,
$('.class').bind('click', my_json_data.clickHandler);
Just found my own answer, WOW, javascript can be quite powerful, check this out
var call_cache = [];
str_is_function = function(str){
if (jQuery.type(str) !== 'string' || ! /^\s*?function/i.test(str) || ! /\}$/m.test(str)) return false;
return true;
}
String.prototype.apply = function(obj){
if ( ! str_is_function(this) ) return false;
var str = this.toString(), cache_len = call_cache.length;
fn = null;
for(i = 0; i < cache_len; i++){
if (call_cache[i].str === str) {
fn = call_cache[i].fn;
break;
}
}
if (typeof fn != 'function'){
$.globalEval('var fn = ' + str);
call_cache.push({'str': str, 'fn': fn});
cache_len = call_cache.length;
}
args = Array.prototype.slice.call(arguments, 1);
if (typeof args[0] != 'undefined' && args[0].constructor === Array){
args = args[0];
}
return fn.apply(obj, args);
}
String.prototype.call = function(obj){
this.apply(obj, Array.prototype.slice.call(arguments, 1));
}
$('.gap').bind({'mouseover':'function(){ alert("gi");}'});
"function(name){ alert(name); }".call(null, "hi");
"function(name){ alert(name); }".apply(null, ["hello"]);
"function(){ alert('teehee'); }".call(null);
"alert".call(null, "hi"); // wont work
No need to hook any jQuery specific function. When it tries to call() or apply() on a string, it will eval to code/function. the problem is that this is a global modification, and could lead to some client-side havoc if someones find out about it hehe.
what are the caveats in this solution?
精彩评论