examining unknown number of inputs to a javascript function - javascript

I am working with a very poorly documented javascript API, and need to write callback functions where the arguments have not been documented. As an opening step, I need to inspect what gets passed in. If I know that there's only one input I can set the callback function to be
function( stuff ){
console.log(stuff);
}
and work from there. Is there an elegant way to inspect inputs when I don't know how many there are? I could do something like
function(a,b,c,d,e,f){
console.log(a)
console.log(b) // is this undefined?
console.log(c) // how about now?
....
console.log(f) // if this isn't undefined I need to do it again with more args
}
and it will work fine, but it's pretty ugly. Is there a simpler way to find out how many argumetns have been passed to a function?

Loop the arguments object:
function f(){
for(var prop in arguments) {
console.log(arguments[prop]);
}
}
f(1); // logs 1
f(1, 2); // logs 1, then 2
As arguments is an array-like object, you can also iterate it with a regular for loop, based on its length property:
for(var i=0; i<arguments.length; i++) {
console.log(arguments[i]);
}

It looks like you are after arguments, which gives you an array of the arguments passed to the current function:
var f = function() {
console.log(arguments);
}
f(1, '2');
f(1, 2, 3, 4, 5);
(Fiddle)

Use arguments
function unknown() {
for (var i=0;i<arguments.length;i++) {
console.log('arg '+i+' : ',arguments[i]);
}
}
unknown(123, 'test', [1, 2, 3]);
arg 0 : 123
arg 1 : test
arg 2 : [1, 2, 3]

Related

How to get access to function args [duplicate]

In PHP there is func_num_args and func_get_args, is there something similar for JavaScript?
For modern Javascript or Typescript:
class Foo {
reallyCoolMethodISwear(...args) { return args.length; }
}
function reallyCoolFunction(i, ...args) { return args[i]; }
const allHailTheLambda = (...args) => {
return args.constructor == Array;
};
const x = new Foo().reallyCoolMethodISwear(0, 1, 2, 3, 4);
const y = reallyCoolFunction(3, 0, 1, 2, 3, 4, 5, 6);
const z = allHailTheLambda(43110, "world");
console.log(x, y, z); // 5 3 true
For ancient Javascript:
Use arguments. You can access it like an array. Use arguments.length for the number of arguments.
The arguments is an array-like object (not an actual array). Example function...
function testArguments () // <-- notice no arguments specified
{
console.log(arguments); // outputs the arguments to the console
var htmlOutput = "";
for (var i=0; i < arguments.length; i++) {
htmlOutput += '<li>' + arguments[i] + '</li>';
}
document.write('<ul>' + htmlOutput + '</ul>');
}
Try it out...
testArguments("This", "is", "a", "test"); // outputs ["This","is","a","test"]
testArguments(1,2,3,4,5,6,7,8,9); // outputs [1,2,3,4,5,6,7,8,9]
The full details: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments
ES6 allows a construct where a function argument is specified with a "..." notation such as
function testArgs (...args) {
// Where you can test picking the first element
console.log(args[0]);
}
The arguments object is where the functions arguments are stored.
The arguments object acts and looks like an array, it basically is, it just doesn't have the methods that arrays do, for example:
Array.forEach(callback[, thisArg]);
Array.map(callback[, thisArg])
Array.filter(callback[, thisArg]);
Array.slice(begin[, end])
Array.indexOf(searchElement[, fromIndex])
I think the best way to convert a arguments object to a real Array is like so:
argumentsArray = [].slice.apply(arguments);
That will make it an array;
reusable:
function ArgumentsToArray(args) {
return [].slice.apply(args);
}
(function() {
args = ArgumentsToArray(arguments);
args.forEach(function(value) {
console.log('value ===', value);
});
})('name', 1, {}, 'two', 3)
result:
> value === name
> value === 1
> value === Object {}
> value === two
> value === 3
You can also convert it to an array if you prefer. If Array generics are available:
var args = Array.slice(arguments)
Otherwise:
var args = Array.prototype.slice.call(arguments);
from Mozilla MDN:
You should not slice on arguments because it prevents optimizations in
JavaScript engines (V8 for example).
As many other pointed out, arguments contains all the arguments passed to a function.
If you want to call another function with the same args, use apply
Example:
var is_debug = true;
var debug = function() {
if (is_debug) {
console.log.apply(console, arguments);
}
}
debug("message", "another argument")
Similar answer to Gunnar, with more complete example:
You can even transparently return the whole thing:
function dumpArguments(...args) {
for (var i = 0; i < args.length; i++)
console.log(args[i]);
return args;
}
dumpArguments("foo", "bar", true, 42, ["yes", "no"], { 'banana': true });
Output:
foo
bar
true
42
["yes","no"]
{"banana":true}
https://codepen.io/fnocke/pen/mmoxOr?editors=0010
Yes if you have no idea that how many arguments are possible at the time of function declaration then you can declare the function with no parameters and can access all variables by arguments array which are passed at the time of function calling.
In ES6 you can do something like this:
function foo(...args)
{
let [a,b,...c] = args;
console.log(a,b,c);
}
foo(1, null,"x",true, undefined);
Hope this helps:
function x(...args) {
console.log( {...[...args] } );
}
x({a:1,b:2}, 'test');
Output:
{ '0': { a: 1, b: 2 }, '1': 'test' }
Hope this could be the helpful code:
function lazyLoadIcons(){
for(let i = 0; i < arguments.length; i++) {
var elements = document.querySelectorAll(arguments[i]);
elements.forEach(function(item){
item.classList.add('loaded');
});
}
}
lazyLoadIcons('.simple-2col', '.ftr-blue-ad', '.btm-numb');
~ Rahul Daksh
In ES6, use Array.from:
function foo()
{
foo.bar = Array.from(arguments);
foo.baz = foo.bar.join();
}
foo(1,2,3,4,5,6,7);
foo.bar // Array [1, 2, 3, 4, 5, 6, 7]
foo.baz // "1,2,3,4,5,6,7"
For non-ES6 code, use JSON.stringify and JSON.parse:
function foo()
{
foo.bar = JSON.stringify(arguments);
foo.baz = JSON.parse(foo.bar);
}
/* Atomic Data */
foo(1,2,3,4,5,6,7);
foo.bar // "{"0":1,"1":2,"2":3,"3":4,"4":5,"5":6,"6":7}"
foo.baz // [object Object]
/* Structured Data */
foo({1:2},[3,4],/5,6/,Date())
foo.bar //"{"0":{"1":2},"1":[3,4],"2":{},"3":"Tue Dec 17 2013 16:25:44 GMT-0800 (Pacific Standard Time)"}"
foo.baz // [object Object]
If preservation is needed instead of stringification, use the internal structured cloning algorithm.
If DOM nodes are passed, use XMLSerializer as in an unrelated question.
with (new XMLSerializer()) {serializeToString(document.documentElement) }
If running as a bookmarklet, you may need to wrap the each structured data argument in an Error constructor for JSON.stringify to work properly.
References
Structure Clone CommonJS Module
JS Object Clone
MDN: Array.from()

How to write multiple arguments with single variable in Javascript?

I'm using a single structure dynamically for many function as shown below:
Parent[funcName](data, function(err) {
// further operations
});
The variable "data" in the function have 0, 1, 2 or 3 as per the function requirement. It works fine when single argument is passed in "data" but if more than 1, it shows error - "more argument are expected".
So how can I pass multiple arguments by using single variable? Is there any work around?
You can use the spread operator
Parent[funcName](...data, function(err) {
// further operations
});
where data is the array of all the parameters you have passed.
Just make use of the arguments object:
function myFunction() {
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments
or this way:
function foo(...args) {
return args;
}
foo(1, 2, 3); // [1,2,3]
greetings

Javascript Filter Function in a For Loop

I was able to complete the task using .filter() and a For Loop, but not sure why I cannot use the format in my second example. First example works fine.
function destroyer(arr) {
for(i=1; i < arguments.length; i++){
number = arguments[i];
arr = arr.filter(function(num){
return num !== number;
});
}
return arr;
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
Tried to replace the return num !== number; with return num!==arguments[i] but the arguments[i] does not appear to return the numeric value.
Because arguments refers to a different functions arguments at that point.
Every time you enter a function, arguments will refer to the currently executing functions arguments. It wouldn't make much sense for arguments to only refer to the top-level functions arguments.
Example:
function a() {
console.log(arguments[0]);
var b = function() {
console.log(arguments[0]);
};
b('This is b');
}
a('This is a');

Javascript:What's the differences between formal parameter and arguments object?

Here is the test code:
function fn(i, j) {
arguments = [3, 4];
console.log(i, j); // 1, 2
console.log(arguments); // [3, 4]
}
fn(1, 2);
in the function , I reset the arguments object
However, the arguments object is changed, but the formal parameter which passed in is not chaned, I think they are the same, so what's the differences?
arguments is an array-like object, which has reference to all the parameters passed to it. Here, you have merely reassigned arguments to point to some other object. If you want to change the actual parameters, you have to change the elements of arguments, like this
function fn(i, j) {
arguments[0] = -1;
console.log(i, j); // -1, 2
console.log(arguments); // { '0': -1, '1': 2 }
}
fn(1, 2)
Quoting from arguments, MDN docs
The arguments object is not an Array. It is similar to an Array, but
does not have any Array properties except length. For example, it does
not have the pop method.
However it can be converted to a real Array:
var args = Array.prototype.slice.call(arguments);
If Array generics
are available, one can use the following instead:
var args = Array.slice(arguments);
You are replacing the arguments array (actually an array-like object) with a new array. They are separate objects and exist side by side. Replacing the reference of the arguments variable doesn't make the function use the new array as arguments, it still has an internal reference to the original object.
If you change the contents of the arguments object, it will reflect on the function arguments:
function fn(i, j) {
arguments[0] = 3;
arguments[1] = 4;
console.log(i, j); // 3, 4
console.log(arguments); // [3, 4]
}
fn(1, 2);

Passing arbitrary number of parameter to a function in javascript

I would like to write a javascript function that works something like this...
f([["a"]], function(e){alert(e);});
// results in alert("a");
f([["a"], ["b"]], function(e1,e2){alert(e1 + ":" + e2);});
//results in alert("a:b");
f([["a", "b"], ["c"]], function(e1,e2){alert(e1 + ":" + e2);});
//results in alert("a:c");alert("b:c");
I can think of a recursive solution for the looping, but how do I send a "unknown" number of variables to a function?
If you put all your arguments into an array (lets call it foo), you can call a function fn with those arguments by using the apply-function.
fn.apply(null, foo)
The first argument (null in this case) is whatever you want this to be inside of the called function. null will probably work for you.
According to this page, you can access any/all arguments using the arguments variable:
function f() {
for( var i = 0; i < arguments.length; i++ ) {
//do something with arguments[i]
}
}
[EDIT]
Now that I understand what you're trying to do, here's a (dirty) way to do it:
Seriously, don't do it this way. It's horrible. Puppies will die.
function f(arr, fn) {
var s = "fn(";
for( var i = 0; i < arr.length; i++ ) {
//you can implement your recursive code here if you like; I'm just doing the base cases
s += arr[i];
if(i+1 < arr.length) {
s += ",";
}
}
s += ");";
eval(s);
}
And for a cleaner way:
function f(arr, fn) {
fn.apply(this, arr);
}
Within the function you can use the variable arguments to see what was passed. IE
function blah() {
console.log(arguments);
}
blah(1, 2); // [1, 2]
blah([1, 2], [3]); // [[1,2], [3]]
blah(1, [2, 3], "string"); // [1, [2, 3], "string"]
You can use the arguments variable that each function has to go through all the passed in arguments.
function myConcat(separator) {
var result = ""; // initialize list
// iterate through arguments
for (var i = 1; i < arguments.length; i++) {
result += arguments[i] + separator;
}
return result;
}
See this article for a discussion of variable number of arguments.
You can use the arguments pseudo-array available within the function to get the arguments passed in without declaring them explicitly (i,e. regardless of whether you define an argument for a function, you can access everything passed in to the function via the arguments implicit variable within that function).

Categories