-1

Is there a clever way to figure out all attributes of an object referenced within a function WITHOUT executing it?

For example let's say I have the following function:

var fun = function(a){
  a.text = "hello world";
  a.title = "greetings";
  a.ran = "fun";
}

I would like some magical function that does:

var results = magical_function(fun, {});
// results = ["text", "title", "ran"];

Basically it's returning all attributes of the argument object that will be accessed inside the fun function, WITHOUT having to actually execute fun.

I said "without running" it because I don't want the act of checking this affect any outside app logic, but I am fine as long as the checking doesn't influence the outside world.

Vlad
  • 8,038
  • 14
  • 60
  • 92
  • `fun.toString()` probably, and parse it somehow. – Egor Stambakio May 17 '17 at 14:29
  • Pass a dummy variable to `fun` and examine its results, then discard the dummy? (Assuming `fun` is idempotent. If not, all bets are off) – Daniel Beck May 17 '17 at 14:29
  • That magical function is called: Object.keys(myObj) – F.bernal May 17 '17 at 14:30
  • @F.bernal can you elaborate on `Object.keys(myObj)`? I am specifically trying to find only the keys that will have been modified when that function is run WITHOUT actually running the function. – Vlad May 17 '17 at 14:34
  • You could always manually define what changes doing something like fun.attributes = ["text", "title", "ran"] and your function just returns that property – juvian May 17 '17 at 14:35
  • @wostex yeah that was my first thought, but realized this is too limited because then I would only be able to detect updates of variables in their exact format, for example once i do something like `var self = this` in the function, it all breaks down – Vlad May 17 '17 at 14:36
  • I don't know if you can do this without running, but here has some solutions http://stackoverflow.com/questions/684672/how-do-i-loop-through-or-enumerate-a-javascript-object – ℛɑƒæĿᴿᴹᴿ May 17 '17 at 14:37
  • do you want to know what attributes a function is going to modify from an object without execute the function? you should get the keys of the object and the parse the function with toString() looking for '.key' – F.bernal May 17 '17 at 14:37
  • @F.bernal yes that's it. – Vlad May 17 '17 at 14:39

3 Answers3

2

function.toString() is going to return a parsable string. Use Regex on that.

var fun = function(a){
  a.text = "hello world";
  a.title = "greetings";
  a.ran = "fun";
}

var fun2 = function(x){
  x.text = "hello world";
  x.title = "greetings";
  a.ran = "fun";
}

function magical_function(func) {
  var data = func.toString();

  var r = /a\.([a-z]+)/g;

  var matches = [];
  var match;
  while ((match = r.exec(data)) != null) {
      matches.push(match[1]);
  }

  return matches;
}

function magical_function_2(func) {
  var data = func.toString();
  
  var attribute_finder_r = new RegExp('function \\(([a-z]+)\\)');
  var attribute_name_match = attribute_finder_r.exec(data);
  
  if (!attribute_name_match) {
    throw 'Could not match attribute name';
  }
  
  var attribute_name = attribute_name_match[1];

  var r = new RegExp(attribute_name + '.([a-z]+)', 'g');

  var matches = [];
  var match;
  while ((match = r.exec(data)) != null) {
      matches.push(match[1]);
  }

  return matches;
}

console.log(magical_function(fun));
console.log(magical_function_2(fun2));
Sergiu Paraschiv
  • 9,929
  • 5
  • 36
  • 47
  • 2
    While this certainly works for this particular case, there are hundreds of border cases where it won´t work. If he intends to follow this route, its practically making a part of javascript interpreter – juvian May 17 '17 at 14:38
  • Thanks for the answer, but this only works for cases where you have control over the variable names inside the function. For example once you have any other functions that use other variable names inside it stops working... – Vlad May 17 '17 at 14:39
  • 1
    @juvian It's a starting point and an answer to the question. I don't know of any other way, except him completely refactoring his codebase so he doesn't need anything like this. Simple question -> simple answer. If he needs advice on how to avoid this then he can ask for it :) – Sergiu Paraschiv May 17 '17 at 14:39
  • 1
    @Vlad Then please post more examples so we know what the "real" use cases are. Only limitation on this is that Regex. And you can definitely get more creative with that. As juvian said above the only solution that would work for _any_ code would be a real JS parser. *And then you're better of just running the function on a deep clone of the input object and comparing input/output*. – Sergiu Paraschiv May 17 '17 at 14:42
  • @SergiuParaschiv Good approach! +1 – ℛɑƒæĿᴿᴹᴿ May 17 '17 at 14:43
0
var myObj = {
    text: '',
  title: '',
  ran: ''
}

var fun = function(a){
  a.text = "hello world";
  a.title = "greetings";
  a.ran = "fun";
}

function magical_function(func, obj) {
  var data = func.toString();

    var keys = Object.keys(obj);
    var regExp = '';

    for (let i= 0; i < keys.length; i++) {
    if (keys.length > 1 && ((i+1) < keys.length)) {
        regExp += keys[i] + '|';
    }
    else if (keys.length == 1 || ((i+1) == keys.length)) {
        regExp += keys[i];
    }
  }

  regExp = '\.(['+ regExp +']+)\\s*=';

  var r = new RegExp(regExp, 'g');

  var matches = [];
  var match;
  while ((match = r.exec(data)) != null) {
    if (Object.keys(obj).includes(match[1]))
        matches.push(match[1]);
  }

  return matches;
}

console.log(magical_function(fun, myObj));
F.bernal
  • 2,594
  • 2
  • 22
  • 27
  • if myObj is empty before entering the function, this wouldn´t work – juvian May 17 '17 at 15:00
  • @juvian that's true but you need to know the keys if you want to be sure that they are related with the object you are modiifying if there is not that relationship you only need to parse functions looking for ".KEY" an assume that the object is being modified... is a little strange problem... but all depends on what you want to achieve... this is just an approach assuming your object is defined. – F.bernal May 17 '17 at 15:06
  • adding this regExp is even better regExp = '\.(['+ regExp +']+)\\s*='; – F.bernal May 17 '17 at 15:13
-4

There's no way those attributes are going to get set before running the function.

The only thing you can do is to write another version of the function which only accesses the object passed and returns the result.

Andrea Borzi
  • 164
  • 3
  • 12