1

I have a function that currently returns an object containing subfunctions.

let myFunction = (data) => {
  return {
    a: function(){
      return a()
    },
    b: function(){
      return b()
    }
  }
}

let a = () => {
  return 'a'
}

let b = () => {
  return 'b'
}

console.log(myFunction().a())
//=> 'a'

console.log(myFunction())

It works perfectly. However, when I run myFunction(), it returns { a: [Function: a], b: [Function: b] }. I would like myFunction() to return another function, alphabet, which returns a string of the alphabet.

Example (obviously not working):

let myFunction = (data) => {
  // CHANGED BELOW
  return alphabet() && {
    a: function(){
      return a()
    },
    b: function(){
      return b()
    }
  }
}

let a = () => {
  return 'a'
}

let b = () => {
  return 'b'
}

let alphabet = () => {
  return 'abcdefghijklmnopqrstuvwxyz'
}

console.log(myFunction().a())
//=> 'a'

console.log(myFunction())
//=> {a: [function a], b: [function b]}

How can I get the function to default to returning one function, while also having the sub-functions available?

Help appreciated. Thanks

1
  • I'm struggling to understand the end result you're looking for. In particular, your second code snippet with what you want (although not working as you said) shows {a: [function a], b: [function b]} as the desired(?) output of calling myFunction()...? Commented Jan 13, 2021 at 18:53

2 Answers 2

2

I think you're saying that you want myFunction to return a function that returns the alphabet, but which also has a and b functions on it.

You can do that, since functions are objects, and objects can have arbitrary properties. There's no literal syntax for functions plus properties, but you can easily add them via assignment or with Object.assign:

let myFunction = (data) => Object.assign(
    () => "abcdefghijklmnopqrstuvwxyz",
    {a, b}
);
    
let a = () => {
    return "a";
};

let b = () => {
    return "b";
};

console.log(myFunction().a());
//=> "a"

console.log(myFunction()());
//                      ^^−−−−−−−−−−− Note the extra ()
//=> "abcdefghijklmnopqrstuvwxyz"

For clarity, here's a more verbose version of myFunction:

let myFunction = (data) => {
    const alphabet = () => "abcdefghijklmnopqrstuvwxyz";
    alphabet.a = a;
    alphabet.b = b;
    return alphabet;
);

The original above does the same thing (other than that this more verbose version gives alphabet a name), but this version may be easier to read.

Or you can have the name like this, too:

let myFunction = (data) => {
    const alphabet = () => "abcdefghijklmnopqrstuvwxyz";
    return Object.assign(alphabet, {a, b});
);

In a comment you've said:

I would like to call myFunction() without the extra ()'s and get the full alphabet

That's basically not possible. You can get close, but you can't literally get there.

The "close" you can get to is that you can return a String object rather than a string primitive:

let myFunction = (data) => Object.assign(
    new String("abcdefghijklmnopqrstuvwxyz"),
    {a, b}
);
    
let a = () => {
    return "a";
};

let b = () => {
    return "b";
};

console.log(myFunction().a());
//=> "a"

console.log(myFunction());
//=> "abcdefghijklmnopqrstuvwxyz"

String objects are objects, not just string primitives, which means they can have additional properties, like a and b. But any time they're coerced to a primitive form, they go back to being a string primitive. For instance, if you use + on them. Also, String objects have all the String methods (they get them from the same place string primitives do), and the ones that return strings return string primitives, so calling (for instance) toLowerCase on the result also gives you a string primitive. Here's an example of both + and toLowerCase():

let myFunction = (data) => Object.assign(
    new String("abcdefghijklmnopqrstuvwxyz"),
    {a, b}
);
    
let a = () => {
    return "a";
};

let b = () => {
    return "b";
};

console.log(myFunction().a());
//=> "a"

console.log("alphabet: " + myFunction());
//=> "abcdefghijklmnopqrstuvwxyz"

console.log(myFunction().toLowerCase());
//=> "abcdefghijklmnopqrstuvwxyz"

I do not recommend doing this. Again, String objects are objects, not the usual kind of strings, and that will likely cause some trouble in your program at some point.

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

21 Comments

I think the OP is asking for (and you're supplying) one more level of indirection than is needed. I think the OP might wish to pass a parameter to myFunction and have it return any of those letter-producing functions (not an object) as result. The default -- no parameter -- would result in the whole-alphabet function.
@danh - Yeah, it's really hard to say.
@T.J.Crowder, Thanks for answering! I think this is as close as I can get to my solution. I would prefer if I could return the value and not call the extra () (e.g. myFunction() instead of myFunction()(). Is this possible? Thanks
@danh yes, that is what I would like. When you specify the sub-function you want, you get the letter back (myFunction().a() => 'a') but when you call myFunction() you get abcdefghijklmnopqrstuvwxyz back (myFunction() => 'abcdefghijklmnopqrstuvwxyz'
Perhaps as I've answered, @imaginate? Though this post by TJCrowder answer is a perfectly sensible interpretation of the question as well.
|
1

EDIT

I think I understand now, reading your comment, but I worry you are asking for something impossible. In a way, you're saying: "I want my function to return an object if the code that follows the invocation dereferences that object". Broken into syntax equivalent lines, you're saying...

let iWantAnObject = myFunction()
iWantAnObject.a() // => 'a'  it works!

let iWantAFunction = myFunction() // same invocation of myFunction, here, it needs to know about the next line of code
iWantAFunction() // oh no, I can't invoke an object :-(

The only idea I have is to pass a param to myFunction to let it know what you want, to let it know what you plan to do with what it returns.

original...

An alternative idea is to return a function, not an object, selected by the parameter...

let myFunction = (data) => {
  const letterFunctions = {
    a: function(){
      return 'a'
    },
    b: function(){
      return 'b'
    }
  }
  const allLettersFn = () => 'abcdefg...'
  return data ? letterFunctions[data] : allLettersFn;
}

let fnB = myFunction('b')
let fnAll = myFunction()

console.log(fnB)
console.log(fnB())

console.log(fnAll)
console.log(fnAll())

1 Comment

Thanks for responding! Sorry if I was unclear, I don't want to return values based upon the data parameter, the data parameter is unused. For example: myFunction('a') doesnt return anything but myFunction().a() returns 'a'. Thanks!

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.