可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
This question already has answers here:
Closed 2 years ago.
For example, if I have the following function in javascript:
var f1 = function(a, b, c) {}
console.log(f1.length); // 3
But with this function, the output is different:
var f2 = function(a, b, c = 6) {}
console.log(f2.length); // 2
How do I count number of arguments of f2
INCLUDING optional arguments?
回答1:
Well, it's a bit of a mess but I believe this should cover most edge cases.
It works by converting the function to a string and counting the commas, but ignoring commas that are in strings, in function calls, or in objects/arrays. I can't think of any scenarios where this won't return the proper amount, but I'm sure there is one, so this is in no way foolproof, but should work in most cases.
function getNumArgs(func) {
var funcStr = func.toString();
var commaCount = 0;
var bracketCount = 0;
var lastParen = 0;
var inStrSingle = false;
var inStrDouble = false;
for (var i = 0; i < funcStr.length; i++) {
if (['(', '[', '{'].includes(funcStr[i]) && !inStrSingle && !inStrDouble) {
bracketCount++;
lastParen = i;
} else if ([')', ']', '}'].includes(funcStr[i]) && !inStrSingle && !inStrDouble) {
bracketCount--;
if (bracketCount < 1) {
break;
}
} else if (funcStr[i] === "'" && !inStrDouble && funcStr[i - 1] !== '\\') {
inStrSingle = !inStrSingle;
} else if (funcStr[i] === '"' && !inStrSingle && funcStr[i - 1] !== '\\') {
inStrDouble = !inStrDouble;
} else if (funcStr[i] === ',' && bracketCount === 1 && !inStrSingle && !inStrDouble) {
commaCount++;
}
}
// Handle no arguments (last opening parenthesis to the last closing one is empty)
if (commaCount === 0 && funcStr.substring(lastParen + 1, i).trim().length === 0) {
return 0;
}
return commaCount + 1;
}
Here are a few tests I tried it on: https://jsfiddle.net/ekzuvL0c/
回答2:
A bit workaround but you can do like this.
function sum(x,y,z){
return {
result:x+y,
length:arguments.length
}
}
var x = sum(1,2);
document.body.innerText = x.result + " | " + x.length;
回答3:
Hmm Coming from Mozilla Web Docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/length
It looks like because the variable is actually passed into the function and not defined as optional argument, the length method works. But since you have optional argument the length method does not pick up the optional argument.
A workaround could be checking if the argument passed within the argument so console.log each argument then see what they output. remember that you could also pass in a function so instead of c=6, this could be converted to another external function where basically you return c which = 6 within that other function then it gets put into the new function as (a,b,c)
Edit: Yea I just checked and it looks like your optional argument is not even in the function. also you don't describe how the function is being called. f2(1,1,c=6) You are not calling the function properly. f2(1,1,c=6); will give you the entire result. not having 2 established arguments and then trying to define the third parameter within the function
回答4:
It gets even better. Try moving the default param for instance…
var f3 = function(a, b = 6, c) {}
console.log(f3.length); // => 1
Or giving it a rest/spread…
var f4 = function(...args) {}
console.log(f4.length); // => 0
But that's cool because someone left us Function.toString
you can use to print out the string representation of the entire function and then write some regex against to reliably get the length for at least the next year.
回答5:
I don't know if this is the best way but what about
f2.toString().split(',').length
Edit: Well if there's commas INSIDE the function this wouldn't work, may need to regexp it a bit more.
How about:
f2.toString().match(/^function\s*\(([^)]+)\)/)[1].split(',').length
回答6:
Outside the function, I think the only way now is to parse the definition, something like this works:
var f1 = function(a, b, c = 6) {console.log(",,,,,,")}
console.log(f1.toString().split("{")[0].match(/,/g).length+1)