I need to test whether the value of a form's onsubmit is a function. The format is typically onsubmit="return valid();". Is there a way to tell if this is a function, and if it's callable? Using typeof just returns that it's a string, which doesn't help me much.
EDIT: Of course, I understand that "return valid();" is a string. I've replaced it down to "valid();", and even "valid()". I want to know if either of those is a function.
EDIT: Here's some code, which may help explain my problem:
$("a.button").parents("form").submit(function() {
var submit_function = $("a.button").parents("form").attr("onsubmit");
if ( submit_function && typeof( submit_function.replace(/return /,"") ) == 'function' ) {
return eval(submit_function.replace(/return /,""));
} else {
alert("onSubmit is not a function.\n\nIs the script included?"); return false;
}
} );
EDIT 2: Here's the new code. It seems that I still have to use an eval, because calling form.submit() doesn't fire existing onsubmits.
var formObj = $("a.button").parents("form");
formObj.submit(function() {
if ( formObj[0].onsubmit && typeof( formObj.onsubmit ) == 'function' ) {
return eval(formObj.attr("onsubmit").replace(/return /,""));
} else {
alert("onSubmit is not a function.\n\nIs the script included?");
return false;
}
} );
Suggestions on possibly how to do this better?
I'm replacing a submit button with an
anchor link. Since calling
form.submit() does not activate
onsubmit's, I'm finding it, and
eval()ing it myself. But I'd like to
check if the function exists before
just eval()ing what's there. – gms8994
<script type="text/javascript">
function onsubmitHandler() {
alert('running onsubmit handler');
return true;
}
function testOnsubmitAndSubmit(f) {
if (typeof f.onsubmit === 'function') {
// onsubmit is executable, test the return value
if (f.onsubmit()) {
// onsubmit returns true, submit the form
f.submit();
}
}
}
</script>
<form name="theForm" onsubmit="return onsubmitHandler();">
<a href="#" onclick="
testOnsubmitAndSubmit(document.forms['theForm']);
return false;
"></a>
</form>
EDIT : missing parameter f in function testOnsubmitAndSubmit
The above should work regardless of whether you assign the onsubmit HTML attribute or assign it in JavaScript:
document.forms['theForm'].onsubmit = onsubmitHandler;
Try
if (this.onsubmit instanceof Function) {
// do stuff;
}
You could simply use the typeof operator along with a ternary operator for short:
onsubmit="return typeof valid =='function' ? valid() : true;"
If it is a function we call it and return it's return value, otherwise just return true
Edit:
I'm not quite sure what you really want to do, but I'll try to explain what might be happening.
When you declare your onsubmit code within your html, it gets turned into a function and thus its callable from the JavaScript "world". That means that those two methods are equivalent:
HTML: <form onsubmit="return valid();" />
JavaScript: myForm.onsubmit = function() { return valid(); };
These two will be both functions and both will be callable. You can test any of those using the typeof operator which should yeld the same result: "function".
Now if you assign a string to the "onsubmit" property via JavaScript, it will remain a string, hence not callable. Notice that if you apply the typeof operator against it, you'll get "string" instead of "function".
I hope this might clarify a few things. Then again, if you want to know if such property (or any identifier for the matter) is a function and callable, the typeof operator should do the trick. Although I'm not sure if it works properly across multiple frames.
Cheers
What browser are you using?
alert(typeof document.getElementById('myform').onsubmit);
This gives me "function" in IE7 and FireFox.
using a string based variable as example and making use instanceof Function
You register the function..assign the variable...check the variable is the name of function...do pre-process... assign the function to new var...then call the function.
function callMe(){
alert('You rang?');
}
var value = 'callMe';
if (window[value] instanceof Function) {
// do pre-process stuff
// FYI the function has not actually been called yet
console.log('callable function');
//now call function
var fn = window[value];
fn();
}
Make sure you are calling typeof on the actual function, not a string literal:
function x() {
console.log("hi");
}
typeof "x"; // returns "string"
typeof x; // returns "function"
You can try modifying this technique to suit your needs:
function isFunction() {
var functionName = window.prompt('Function name: ');
var isDefined = eval('(typeof ' + functionName + '==\'function\');');
if (isDefined)
eval(functionName + '();');
else
alert('Function ' + functionName + ' does not exist');
}
function anotherFunction() {
alert('message from another function.');
}
form.onsubmit will always be a function when defined as an attribute of HTML the form element. It's some sort of anonymous function attached to an HTML element, which has the this pointer bound to that FORM element and also has a parameter named event which will contain data about the submit event.
Under these circumstances I don't understand how you got a string as a result of a typeof operation. You should give more details, better some code.
Edit (as a response to your second edit):
I believe the handler attached to the HTML attribute will execute regardless of the above code. Further more, you could try to stop it somehow, but, it appears that FF 3, IE 8, Chrome 2 and Opera 9 are executing the HTML attribute handler in the first place and then the one attached (I didn't tested with jQuery though, but with addEventListener and attachEvent). So... what are you trying to accomplish exactly?
By the way, your code isn't working because your regular expression will extract the string "valid();", which is definitely not a function.
If it's a string, you could assume / hope it's always of the form
return SomeFunction(arguments);
parse for the function name, and then see if that function is defined using
if (window[functionName]) {
// do stuff
}
Isn't typeof xxx === 'function' the best and the fastest?
I made an bench in wich you can try it out, compared to instanceof and _underscore
Its just seems to be faster than instanceof (using chrome)
It won't trow an error if the variable is not defined
Here a bench: https://jsbench.me/qnkf076cqb/1
Checking the call method on the value seems to be a good enough test. e.g., val.call && val()
> a = () => {}
[Function: a]
> function b() {}
undefined
> c = function(){}
[Function: c]
> d = 2
2
> e = []
[]
> f = {}
{}
> a.call
[Function: call]
> b.call
[Function: call]
> c.call
[Function: call]
> d.call
undefined
> e.call
undefined
> f.call
undefined
Note: Except when it's a class.
Well, "return valid();" is a string, so that's correct.
If you want to check if it has a function attached instead, you could try this:
formId.onsubmit = function (){ /* */ }
if(typeof formId.onsubmit == "function"){
alert("it's a function!");
}
You can always use one of the typeOf functions on JavaScript blogs such as Chris West's. Using a definition such as the following for the typeOf() function would work:
function typeOf(o){return {}.toString.call(o).slice(8,-1)}
This function (which is declared in the global namespace, can be used like this:
alert("onsubmit is a " + typeOf(elem.onsubmit));
If it is a function, "Function" will be returned. If it is a string, "String" will be returned. Other possible values are shown here.
I think the source of confusion is the distinction between a node's attribute and the corresponding property.
You're using:
$("a.button").parents("form").attr("onsubmit")
You're directly reading the onsubmit attribute's value (which must be a string). Instead, you should access the onsubmit property of the node:
$("a.button").parents("form").prop("onsubmit")
Here's a quick test:
<form id="form1" action="foo1.htm" onsubmit="return valid()"></form>
<script>
window.onload = function () {
var form1 = document.getElementById("form1");
function log(s) {
document.write("<div>" + s + "</div>");
}
function info(v) {
return "(" + typeof v + ") " + v;
}
log("form1 onsubmit property: " + info(form1.onsubmit));
log("form1 onsubmit attribute: " + info(form1.getAttribute("onsubmit")));
};
</script>
This yields:
form1 onsubmit property: (function) function onsubmit(event) { return valid(); }
form1 onsubmit attribute: (string) return valid()
// This should be a function, because in certain JavaScript engines (V8, for
// example, try block kills many optimizations).
function isFunction(func) {
// For some reason, function constructor doesn't accept anonymous functions.
// Also, this check finds callable objects that aren't function (such as,
// regular expressions in old WebKit versions), as according to EcmaScript
// specification, any callable object should have typeof set to function.
if (typeof func === 'function')
return true
// If the function isn't a string, it's probably good idea to return false,
// as eval cannot process values that aren't strings.
if (typeof func !== 'string')
return false
// So, the value is a string. Try creating a function, in order to detect
// syntax error.
try {
// Create a function with string func, in order to detect whatever it's
// an actual function. Unlike examples with eval, it should be actually
// safe to use with any string (provided you don't call returned value).
Function(func)
return true
}
catch (e) {
// While usually only SyntaxError could be thrown (unless somebody
// modified definition of something used in this function, like
// SyntaxError or Function, it's better to prepare for unexpected.
if (!(e instanceof SyntaxError)) {
throw e
}
return false
}
}
if ( window.onsubmit ) {
//
} else {
alert("Function does not exist.");
}
Beware that es6 class is also a function but not callable
class C {}
typeof C === "function" // true
C instanceof Function // true
C() // error
C.call() // error
new C() // okay
new C // okay
A simple check like this will let you know if it exists/defined:
if (this.onsubmit)
{
// do stuff;
}
Related
So I really couldn't find much on this. The idea is that I have a user input (text) and I want to check if its valid code in JS and then run it if it is.
I know that I can do if (typeof userInput === "function") { if the userInput was actually a function, but the user input is just a string input at this point, so I'm quite stuck, and it also contains any arguments or other code.
As an example, the input may be "alert('test')" and that would be valid, and I would like to run that, however something like "madeUpFunction(lol)" would be invalid.
I'm happy if I can just get functions working and not any JS code.
You can extract the string up until the first ( in order to get the function name, and then test that it exists using typeof eval(funcName). Then use the Function constructor to make sure that the syntax is valid for the rest of the arguments without actually executing the code.
You can then return the function which executes what the user entered, but note that there may be security issues if you decide to execute the function.
function parseFunctionCall(str) {
var funcName = str.slice(0, str.indexOf('('));
if (typeof eval(funcName) === 'function') {
return new Function(str);
} else {
throw new Error('Invalid function name');
}
}
console.log(parseFunctionCall("console.log('hi')"));
You can use eval("typeof "+ input) to achieve what you want. The argument of the eval() function is a string. If the string represents an expression, eval() evaluates the expression.
var myFunc = function(){};
var input = prompt('Enter input string');
if(eval("typeof "+input) === "function"){
document.getElementById('d1').innerHTML = "Yes it's a funtion";
}
else{
document.getElementById('d1').innerHTML = "Not a funtion";
}
<div id="d1">
</div>
Assuming this is in a browser and that that function you want to check is in the global scope:
if (typeof window[userInput] === "function" ) {
...
}
I have QML code, for example this code
Item {
id:self;
function update(){
var visitFunc = self.applyUpdate;
innerTraversal(self,visitFunc);
}
function reset(){
var visitFunc = self.applyReset;
innerTraversal(self,visitFunc);
}
function innerTraversal(obj, visitFun){
console.log(typeof visitFun);
if(obj!== self && visitFun && typeof visitFun ==="function")
visitFun(obj);
if(hasChilderns(obj)){
var objChilderns = obj.children;
for(var i=0 ; i< objChilderns.length ; i++){
innerTraversal(objChilderns[i]);
}
}
}
function hasChilderns(obj){
if(typeof obj.children !== 'undefined')
return true;
else
return false;
}
function applyReset(obj){
if(typeof obj.reset === 'function')
obj.reset();
}
function applyUpdate(obj){
if(typeof obj.update === 'function')
obj.update();
}
}
in normal javascript this works cool, but when I use this code in QML the bad thing is visitFun always has type of undefined, and it does not work..
any idea how to make this work ?
In QtQuick 2 you should be able to bind functions to properties using
Item { //<-- declaration
id : item
property variant fun
}
item.fun : Qt.binding(function(){doSomething()}) //<--defintion
item.fun // <-- invocation without braces
So you could pass an object with a generic function as parameter.
In general, function overloading a can also be used to create a generic function for example to create a Button type:
---Button.qml
Item {
function fun() {} //<-- declaration (empty dummy)
MouseArea {
anchors.fill: parent
onClicked: {
fun(); //<-- invocation
}
}
}
---
---main.qml---
Button {
id: button
function fun() { //<-- defintion by overloading
doSomething
}
}
---
Clicking the button will activate its onClick handler and actually do something ;). Again, you would then pass the object with the generic function not the function itself.
In QML internals your "self" has type "QQuickItem", while normal JS object (created with "new Object()" or "{"prop" : "value"}", for example) has type QJsValue. And "self" isn't variable name, it's QML id, keep in mind that defference.
In QML the using of signals\slots or property bindings can be much more powerful rather than passing callback like in "normal" JS. The using of "typeof" is also bad practice (as far as I know in "normal" JS too), you can simply write something like:
// Or simply "return obj.children" - but function become useless than.
if(obj.children)
return true;
else
return false;
But this code still useless - Item's property "children" in QML has type "list", it always exists.
So my conclusion - you should try to learn some QML basics before writing something.
I was simply practicing a little bit of JavaScript. My goal was to create a function that can call another function with the .invoke() until .revoke() is called, which then nullifies the function.
Later on, I've added .porcupine() which was, in theory, supposed to take the firstly invoked function (in this case, alert()) and then reapply it to the original "temp". The issue is, though, after being revoked temp becomes unknown, therefore it can not call anything anymore. Is there something very obvious to this that I'm missing out or will the solution have to be fairly messy?
var denullifier;
function revocable(unary) {
if (denullifier === null)
denullifier = unary;
return {
invoke: function(x) {
return unary(x);
},
revoke: function() {
var nullifier = unary;
unary = null;
return nullifier.apply(this, arguments);
},
porcupine: function() {
unary = denullifier;
return unary.apply(denullifier, arguments);
}
};
};
console.log('----------');
temp = revocable(alert);
temp.invoke(7); ///alerts 7
temp.revoke();
temp.porcupine(); //exception
temp.invoke(7); //doesn't get here
I don't quite understand what you're doing, but there are a few problems with your code.
if (denullifier === null)
denullifier = unary;
denullifier is not null here, it's undefined - so the condition isn't met.
return nullifier.apply(this, arguments);
You can't call alert this way, the first param must be null or window.
return unary.apply(denullifier, arguments);
The same.
This is your problem:
var denullifier;
function revocable(unary) {
if (denullifier === null)
denullifier = unary;
denullifier is undefined when declared without a value. However, you are checking for type-strict equality with null, which will be false, so denullifier is never set and porcupine is not able to restore the unary function.
I'd suggest:
Use == instead of === to get equality with undefined
Even better, use typeof denullifier != "function"
Or, (although I don't know your design) you should not make denullifier a global, static variable that will be shared amongst revocable instances, but instead make it instance-specific by putting the declaration inside the function body.
When you call a function in JavaScript and you miss to pass some parameter, nothing happens.
This makes the code harder to debug, so I would like to change that behavior.
I've seen
How best to determine if an argument is not sent to the JavaScript function
but I want a solution with a constant number of typed lines of code; not typing extra code for each function.
I've thought about automatically prefixing the code of all functions with that code, by modifying the constructor of the ("first-class") Function object.
Inspired by
Changing constructor in JavaScript
I've first tested whether I can change the constructor of the Function object, like this:
function Function2 () {
this.color = "white";
}
Function.prototype = new Function2();
f = new Function();
alert(f.color);
But it alerts "undefined" instead of "white", so it is not working, so I've don't further explored this technique.
Do you know any solution for this problem at any level? Hacking the guts of JavaScript would be OK but any other practical tip on how to find missing arguments would be OK as well.
If a function of yours requires certain arguments to be passed, you should check for those arguments specifically as part of the validation of the function.
Extending the Function object is not the best idea because many libraries rely on the behavior of defaulting arguments that are not passed (such as jQuery not passing anything to it's scoped undefined variable).
Two approaches I tend to use:
1) an argument is required for the function to work
var foo = function (requiredParam) {
if (typeof requiredParam === 'undefined') {
throw new Error('You must pass requiredParam to function Foo!');
}
// solve world hunger here
};
2) an argument not passed but can be defaulted to something (uses jQuery)
var foo = function (argumentObject) {
argumentObject = $.extend({
someArgument1: 'defaultValue1',
someArgument2: 'defaultValue2'
}, argumentObject || {});
// save the world from alien invaders here
};
As others have said, there are many reasons not to do this, but I know of a couple of ways, so I'll tell you how! For science!
This is the first, stolen from Gaby, give him an upvote! Here's a rough overview of how it works:
//example function
function thing(a, b, c) {
}
var functionPool = {} // create a variable to hold the original versions of the functions
for( var func in window ) // scan all items in window scope
{
if (typeof(window[func]) === 'function') // if item is a function
{
functionPool[func] = window[func]; // store the original to our global pool
(function(){ // create an closure to maintain function name
var functionName = func;
window[functionName] = function(){ // overwrite the function with our own version
var args = [].splice.call(arguments,0); // convert arguments to array
// do the logging before callling the method
if(functionPool[functionName].length > args.length)
throw "Not enough arguments for function " + functionName + " expected " + functionPool[functionName].length + " got " + args.length;
// call the original method but in the window scope, and return the results
return functionPool[functionName].apply(window, args );
// additional logging could take place here if we stored the return value ..
}
})();
}
}
thing(1,2 ,3); //fine
thing(1,2); //throws error
The second way:
Now there is another way to do this that I can't remember the details exactly, basically you overrride Function.prototype.call. But as it says in this question, this involves an infinite loop. So you need an untainted Function object to call, this is done by a trick of turning the variables into a string and then using eval to call the function in an untainted context! There's a really great snippet out the showing you how from the early days of the web, but alas I can't find it at the moment. There's a hack that's required to pass the variables properly and I think you may actually lose context, so it's pretty fragile.
Still, as stated, don't try and force javascript to do something against its nature, either trust your fellow programmers or supply defaults, as per all the other answers.
You can imitate something like Python’s decorators. This does require extra typing per function, though not extra lines.
function force(inner) {
return function() {
if (arguments.length === inner.length) {
return inner.apply(this, arguments);
} else {
throw "expected " + inner.length +
" arguments, got " + arguments.length;
}
}
}
var myFunc = force(function(foo, bar, baz) {
// ...
});
In general this sounds like a bad idea, because you’re basically messing with the language. Do you really forget to pass arguments that often?
You could use the decorator pattern. The following decorator allows you to specify minimum and maximum number of arguments that need to be passed and an optional error handler.
/* Wrap the function *f*, so that *error_callback* is called when the number
of passed arguments is not with range *nmin* to *nmax*. *error_callback*
may be ommited to make the wrapper just throw an error message.
The wrapped function is returned. */
function require_arguments(f, nmin, nmax, error_callback) {
if (!error_callback) {
error_callback = function(n, nmin, nmax) {
throw 'Expected arguments from ' + nmin + ' to ' + nmax + ' (' +
n + ' passed).';
}
}
function wrapper() {
var n_args = arguments.length;
console.log(n_args, nmin, nmax);
console.log((nmin <= 0) && (0 <= nmax));
if ((nmin <= n_args) && (n_args <= nmax)) {
return f.apply(this, arguments);
}
return error_callback(n_args, nmin, nmax);
}
for (e in f) {
wrapper[e] = f[e];
}
return wrapper;
}
var foo = require_arguments(function(a, b, c) {
/* .. */
}, 1, 3);
foo(1);
foo(1, 2);
foo(1, 2, 3);
foo(1, 2, 3, 4); // uncaught exception: Expected arguments from 1 to 3 (4 passed).
foo(); // uncaught exception: Expected arguments from 1 to 3 (0 passed).
I have a json string like this:
json = "{'run': 'function() { console.log('running...'); }'}"
How do I run that function inside of the json string?
You're going to have to use the eval() (doc) function. A lot of people have a lot of feelings about this function. JSON is best for transporting data, not functions (see JSON). The functions ought to lay in the script on the page.
Also there's a syntax error in your posted code (function is wrapped in single quotes ('), and so is console.log's first parameter).
But...
json = "{\"run\":\"function() { console.log('running...'); }\"}"; //Fixed, thanks
obj = JSON.parse(json);
eval(obj.run); //Logs "running..."
Update:
Oh, and I was mistaken. Eval doesn't seem to like anonymous functions. With the revised code, it will parse json into an object with a run property that is a String, with value "function() { console.log('running...'); }". But when you eval(obj.run);, you will get a SyntaxError declaring an unexpected (. Presumably, this is the ( in function ().
So, I can think of two ways of dealing with this:
Remove the anonymous function in your actual JSON string (so, make your PHP forget about function () {), and eval it. This means it will be called as soon as you eval it.
What I think you want, is to be able to evaluate it to an anonymous function, that will be called when you want. So, you could write a wrapper function (you would need to follow option 1 for this as well):
function returnEval(str) {
return function () { eval(str); }
}
This would allow you to call it. So:
obj = JSON.parse(json);
obj.run = returnEval(obj.run);
obj.run(); //Logs "running..."
Hope this helps!
JSON is not really intended for that, but here seems to be a good example.
This works for me in Firefox:
var json = "{'run': 'function() { console.log(\\'running...\\'); }'}";
eval('var j = ' + json);
eval('var r = ' + j.run);
r();
Try this, it works:
var JS = { "function" : "alert( new Date().getTime() );" };
new Function ( "", JS["function"] )();
for nested functions you also can use something like this:
jQuery.each( JS, function( method, value ) {
new Function ( "a, b", "if ( a == 'function' ) { new Function ( '', b )(); }" )( method, value );
} );
I know that thread is old but i want to share with you guys. You can make string a json and parse it easily with these functions.
function makeString(val){
return JSON.stringify(val, function (key, value) {if (typeof value == 'function') {return value.toString();}return value;});
}
function parseIt(val){
return JSON.parse(string, function (key, value) {if (value.toString().search("function")>-1) {eval("var func = " + value);return func;}return value;});
}
Without using eval('function()') you could to create a new function using new Function(strName). The below code was tested using FF, Chrome, IE.
<html>
<body>
<button onclick="test()">Try it</button>
</body>
</html>
<script type="text/javascript">
function test() {
try {
var myJSONObject = {"success" : true, "jsFunc" : "myFunction()"};
var fnName = myJSONObject.jsFunc;
var fn = new Function(fnName);
fn();
} catch (err) {
console.log("error:"+err.message);
}
}
function myFunction() {
console.log('Executing myFunction()');
}
</script>