0

function F (v) {
    var v = v;
    this.fun = function f () {
            console.log(v);
    };
};

var i = new F(1); 

i.fun();

Just to clarify, I don't this my question is solved by a knowledge of closures.

To my understanding, i is just: {fun: function f () {console.log(v)}}.

So how is i.fun() able to access v - one of the variables in a constructor function that only helped to make i?

tonitone110
  • 139
  • 6
  • Why don't you think this is solved by closures? `this.fun` is a closure, and `v` is a variable in the containing scope. Closures save references to the variables in their scope. – Barmar Jun 30 '20 at 01:20
  • BTW, there's no need to write `var v = v`. Parameters are local variables. – Barmar Jun 30 '20 at 01:21

1 Answers1

2

The fact that v is a property of i is irrelevant. In fact it isn't, as a comment points out. (Your v = v just assigns the same value to the same variable and has no function whatsoever.)

The answer is that the value of v is captured when the function is defined in what is called a closure.

kindall
  • 178,883
  • 35
  • 278
  • 309
  • 1
    `v` isn't actually a property of `i` here - it would have been if the first line had been `this.v = v;`. But as you say, it doesn't matter because the variable `v` is stored in the closure. Although it's worth pointing out that there is a difference: with `this.v = v;` the variable becomes a "public property" of `i` - you can access, and indeed alter, that property directly as `i.v`. The beauty of closures in situations like this is they let you define "private" variables - as in the OP's code there is no way to change the `v` variable from outside. – Robin Zigmond Jun 29 '20 at 20:45
  • @RobinZigmond thanks! – kindall Jun 29 '20 at 20:48
  • Thanks @kindall. I understand closures I don't think that's the issue. My understanding is that `i` is a new object. And function f is the only value in this new object because of the line `this.fun`... So surely `fun` would only recognise `v` if `v` also got carried into the new object (with something like `this.v`). – tonitone110 Jun 29 '20 at 21:06
  • 1
    Of course it's a closure. `this.fun` is defined in a function `f`. the variable `v` is a local variable in `f` and is therefore captured in `this.fun`'s closure when it is defined. It's only an object because you used `new` with it. – kindall Jun 29 '20 at 21:10
  • I understand that. But we are not calling `F`. Are we not dealing with a completely new entity: `{fun: function f () {console.log(v)}}`. Isn't this the value of `i`?. Therefore, how does `i.fun()` see its old constructor function that made it and successfully retrieve one of the variables defined in there? – tonitone110 Jun 29 '20 at 21:19
  • Because that's how closures work. It seems that you may not understand the concept as well as you think you do. Since `v` is in the scope of `fun`, `fun` can always access it, even when - as here - it's executing outside that scope. And that's essentially the definition of closure. – Robin Zigmond Jun 29 '20 at 23:37
  • @tonitone110 Why do you think you're not calling `F`? `new F(1)` calls `F`. – Barmar Jun 30 '20 at 01:22
  • @Barmar I just thought that `new F(1)` returns just `{fun: function f () {console.log(v)}}` so `i` is just `{fun: function f () {console.log(v)}}`. So `i.fun();` is referencing `v` which is all the way back in a completely separate function, `F`. I think it's my understanding of what a constructor function with the keyword `new` returns that needs to be improved, not my understanding of closures? Because I totally understand how `fun()` could see `v` if we were just calling function `F()`. – tonitone110 Jun 30 '20 at 11:47
  • The only thing special about calling functions with `new` is that an empty object is created first and passed as `this` context, the function is made to be its prototype, and that object is returned automatically if the function doesn't have an explicit `return` statement. There's nothing different about the closure environment. – Barmar Jun 30 '20 at 13:44
  • @Barmar My understanding was: I know `function f` can see `v` when we are calling `function f` from the constructor function `F`. But it's my understanding `function f ` has been copied over as a value in a brand new object, assigned to `i`. And it is this value we are returning when we type `i.fun();`. Therefore, how does this new `function f` see `v`? I've since been told that `i` is more complex than just `{fun: function f () {console.log(v)}}` even though this is just what the console shows. Problem is I don't know where to look to find out more. Closures with `new` keyword? Prototypes? – tonitone110 Jun 30 '20 at 13:53
  • That's what a closure does -- it saves the environment from where it was called. So `v` is saved in the closure's environment. It's the same with or without the `new` keyword, so the linked question should explain it. – Barmar Jun 30 '20 at 13:55