0

How to check if the string parameter passed in a function is too callable/function but not directly under window..

I know the open/ directly callable function can be checked using the syntax window['functionName']

But how about the member function declared inside an object to be checked?

In below example openFunction() can be called but how to call obj1.foo()?

Prefer not to use eval()

Example Code:

var obj1 = {
  foo: function() {
    alert("I'm a function");
  }
}

function openFunction() {
  alert("I know i am easily callable");
}

function callSomeone(txtcallback) {
  var fn = window[txtcallback];
  if (typeof fn === 'function') {
    fn();
  }
  console.log(typeof fn);
}

callSomeone('openFunction'); //function
callSomeone('obj1.foo'); //undefined

1

3 Answers 3

1

It returns undefined because, your code is equivalent to window["obj1.foo"] which is not correct.

The correct way to access to foo function is window["obj1"]["foo"].

So you have to "cycle" through the string obj1.foo.

Here I added a GetProp function that do that cycle and is recursive, so the level of nesting is not a problem.

var obj1 = {
  foo: function() {
    alert("I'm a function");
  }
}

function openFunction() {
  alert("I know i am easily callable");
}

function callSomeone(txtcallback) {
  var fn = GetProp(window, txtcallback.split("."));
  if (typeof fn === 'function') {
    fn();
  }
  console.log(typeof fn);
}

function GetProp(obj, props) {
  if(props.length == 0) {
    return obj;
  } else if(obj[props[0]] != undefined) {
    obj = obj[props[0]];
    return GetProp(obj, props.slice(1));
  }
}

callSomeone('openFunction'); //function
callSomeone('obj1.foo'); //undefined

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks, i found yours is most professional way of coding solution.
i have extended question on this. if i wants to maintain an index (id) variable/member of the object. calling such way it getting lost it's value. var obj1 = { id: 0, foo: function() { ++this.id; alert("id = " + this.id); } }
In this case, try JsonPath. It should work for your need.
replacing this.id with this.obj1.id or window.obj1.id works. (what is the difference if you can explain.) but why not the syntax according to JsonPath tutorial works $.obj.id works?
1

try this

var obj1 = {
  foo: function() {
    alert("I'm a function");
  }
}

function openFunction() {
  alert("I know i am easily callable");
}

function callSomeone(txtcallback) {
    str =txtcallback.split(".");
    temp = window;
    for(check in str){
        temp = temp[str[check]];
         if (typeof temp === 'function') {
            temp();
            break;
         }else if(typeof temp === 'undefined'){
             break;
         }
    }
  console.log(typeof temp);
}

callSomeone('openFunction'); //function
callSomeone('obj1.foo'); //function

Comments

1

If you ant to look for members inside nested maps you have to use a recursive approach.

function callSomeone(txtcallback) {
  var keyPath = txtcallback.split(".");
  var fn = keyPath.reduce(function (member, key) {
    return member[key];
  }, window);

  if (typeof fn === 'function') {
    fn();
  }
  console.log(typeof fn);
}

the downside in this example is that the function is executed in the global scope. If you need to keep the scope of the container object you need to also save the scope.

var obj1 = {
  foo: function() {
    alert("I'm a function");
    return this;
  }
}

function openFunction() {
  alert("I know i am easily callable");
  return this;
}

function callSomeone(txtcallback) {
  var keyPath = txtcallback.split(".");

  var scope = null;

  var context = null;
  var fn = keyPath.reduce(function (member, key) {
    scope = member;
    return member[key];
  }, window);

  if (typeof fn === 'function') {
    context = fn.call(scope);
  }
  console.log(typeof fn, context);
}

callSomeone('openFunction'); //function
callSomeone('obj1.foo'); //undefined

1 Comment

Normally I would use a library such as lodash to accomplish this. This is merely showing how it could work. In lodash I would probably use _.result. lodash.com/docs#result

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.