Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to identify names of arguments to a function in javascript?

In AngularJS these two controller declarations are equivalent:

function BlahCtrl($scope, $http) { ... }
function BlahCtrl($http, $scope) { ... }

Both $http and $scope will be the correct variables no matter what order they are in. i.e. the variable named $http will always be passed an instance of the $http service.

How does Angular know which objects to pass in and in what order? I thought this kind of reflection was not possible with javascript.

like image 975
Matt York Avatar asked Aug 20 '12 00:08

Matt York


People also ask

How do you find the argument of a function?

You can refer to a function's arguments inside that function by using its arguments object. It has entries for each argument the function was called with, with the first entry's index at 0 . You can use arguments.length to count how many arguments the function was called with.

How do you check if an argument is a function JavaScript?

Use the typeof operator to check if a function is defined, e.g. typeof myFunction === 'function' . The typeof operator returns a string that indicates the type of a value. If the function is not defined, the typeof operator returns "undefined" and doesn't throw an error. Copied!

How can you get the type of arguments passed to a function in JavaScript?

There are two ways to pass arguments to a function: by reference or by value. Modifying an argument that's passed by reference is reflected globally, but modifying an argument that's passed by value is reflected only inside the function.

What is the typeof arguments inside a function in JavaScript?

typeof is a JavaScript keyword that will return the type of a variable when you call it. You can use this to validate function parameters or check if variables are defined. There are other uses as well. The typeof operator is useful because it is an easy way to check the type of a variable in your code.


2 Answers

If you call toString on a function, you get the js declaration of that function:

function a(b,c) {}

a.toString();  // "function a(b,c){}"

then you can parse the string for the order of arguments.

Some investigation into the angular source code confirms this:

if (typeof fn == 'function') {
  if (!($inject = fn.$inject)) {
    $inject = [];
    fnText = fn.toString().replace(STRIP_COMMENTS, '');
    argDecl = fnText.match(FN_ARGS);
    forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
      arg.replace(FN_ARG, function(all, underscore, name){
        $inject.push(name);
      });
    });
    fn.$inject = $inject;
  }
}

They stringify the function, then extract the arguments with a regular expression and store them in an array.

jsFiddle showing how this all works.

like image 122
Dennis Avatar answered Oct 15 '22 10:10

Dennis


Although I don't know how they do it in, there is a simple way to do it.

Everything in JS has toString() method. For functions, it shows the source code of that particular function (for in-built functions, you may get something like function() { [native code] }).

Let us find the first ( and the first ), which enclose the function's arguments. Then, let's strip the whitespaces and split the arguments by ,. Voila, we get an array of argument names.

function a($scope, $http) { };
function b($http, $scope) { };

function getParameterList(f) {
  var s = f.toString();

  var start = s.indexOf('(');
  var end = s.indexOf(')');

  s = s.substring(start + 1, end);

  return s.replace(/ /g,'').split(',');
}

So let's test it:

var aParams = getParameterList(a);
var bParams = getParameterList(b); 

alert(aParams[0]); // $scope
alert(aParams[1]); // $http 

alert(bParams[0]); // $http
alert(bParams[1]); // $scope  

A fiddle: http://jsfiddle.net/jYPB8/

However, note that this behaviour of toString() is defined in Function.prototype and may be redefined - in which case, this algorithm won't work.

So while this may not be the actual solution you were looking for, I wanted to show you that this kind of reflection is possible in JavaScript, and it's actually very simple to do :)

like image 22
Imp Avatar answered Oct 15 '22 12:10

Imp