0

I'm learning JS and am wondering, is there a way to return the function bar() or buz() by without returning foo()? For example, if I wanted to return the function bar(); to get 2, could I do that? Would it be something like foo().bar(); ?

// Nested Scopes
function foo() {  // can only access itself
  var a = 1;

  function bar() {  // access to foo(), not buz()
    var b = 2;

    function buz() {   // access to bar() and foo()
      var c = 3;

      console.log(a, b, c);  // 1, 2, 3
    }
    buz();
    console.log(a, b);  // 1, 2
  }
  bar();
  console.log(a);  // 1
}
foo();  // 1

2
  • What do you mean by "without returning foo()"? Do you mean without console.log(a); executing? Commented Feb 17, 2017 at 4:39
  • I had been trying to do what @Xufox answered. Commented Feb 17, 2017 at 4:46

3 Answers 3

1

Certainly. You can return an object at each stage which holds the function, or you can return the function itself. This utilizes what's called a closure.

function foo() {
  var a = 1;
  
  function bar() {
    var b = 2;
    
    function buz() {
      var c = 3;
      console.log(a, b, c);
    }
    
    console.log(a, b);
    return { buz: buz };
  }
  
  console.log(a);
  return { bar: bar };
}

foo().bar().buz();

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

4 Comments

But then you can't call bar() without it also running the foo() functionality (i.e., you can't log "1 2" without also logging "1"). Maybe making the inner functions to be properties would work better: foo.bar()...
@nnnnnn I can't actually think of a way of implementing that without calling foo. How do you assign those properties?
I'm not sure. My initial thought was "OK, just call foo as part of the setup", but that would have the side effect of logging stuff to the console (or doing whatever some real-world functions do) before any "client" code called the functions.
P.S. Even if you add some first-time-initialisation code, the behaviour still isn't great because the foo.bar and foo.bar.buz properties refer to functions that belong to the closure of the first call to foo: jsfiddle.net/bzbdhnd2
0

You can do this, but it’s quite over-complicated.

The basic syntax is:

foo().bar().buz();

Where-ever you add another () after an existing one, it’ll print that level out. See the snippet for examples.

// Nested Scopes
function foo() { // can only access itself
  var a = 1;

  function bar() { // access to foo(), not buz()
    var b = 2;

    function buz() { // access to bar() and foo()
      var c = 3;

      return (function() {
        console.log(a, b, c);
      });
    }

    return (function() {
      var tmp = function() {
        console.log(a, b);
        return {
          buz: buz
        };
      };
      tmp.buz = buz;
      return tmp;
    })();
  }

  return (function() {
    var tmp = function() {
      console.log(a);
      return {
        bar: bar
      };
    };
    tmp.bar = bar;
    return tmp;
  })();
}


foo().bar().buz(); // (nothing)
foo().bar()().buz(); // 1, 2
foo()().bar()().buz(); // 1  // 1, 2
foo()().bar().buz()(); // 1  // 1, 2, 3
foo()().bar()().buz()(); // 1  // 1, 2  // 1, 2, 3

This kind of abuses the fact that you can assign properties to anything in JavaScript, including functions.

  • foo is a function that refers to the outer foo.
  • foo() is another function that refers to that inner tmp which has a bar property that refers to the inner bar function.
  • foo()() actually calls that inner tmp function but still leaves you with an object that has a bar property that again refers to the inner bar function.

This approach is basically the same for bar.

For buz, however, (something).buz() is just a function, without any extra properties and (something).buz()() doesn’t return anything, because that’s the final level.

2 Comments

Are the IIFEs just there to hide tmp? It does look a bit over-complicated.
@4castle Basically yes. Maybe tmp can just be a normal variable before the return. I’m not sure what could happen then… This can probably be improved…
0

you do this more like setting a variable.

var foo = {

bar: function() { return 3; } }

console.log(foo.bar());

Comments

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.