0

I'm somewhat new to JavaScript and have a few questions about scope that don't seem to have been explicitly asked about before. At the top of a function I'm working on in angular a variable vm is set equal to this. I understand that anything prefaced with vm going forward will be in scope of this however how is this different from being in the function's scope to begin with? To be more explicit, how would vm.foo = "test" differ from var foo = "test" inside of a function in terms of its scope. Any help would be much appreciated.

dusk
  • 43
  • 3
  • 5
  • 3
    Possible duplicate of [JavaScript Variables vs Properties](http://stackoverflow.com/questions/32491231/javascript-variables-vs-properties) – Patrick Evans Jun 01 '16 at 14:53
  • 1
    I don't understand all the downvotes - for a JavaScript / Angular newcomer, the confusion is quite reasonible. – idleherb Jun 01 '16 at 14:59
  • 1
    I'm sure it could be confusing. but.. we're tasked with downvoting poorly researched questions as well as questions that aren't useful. This one falls under at least one of those criteria. – Kevin B Jun 01 '16 at 15:21

2 Answers2

0

If you set vm = this, then properties of vm can persist beyond the scope of the current function invocation. In contrast, a local variable value (e.g., var foo = "test") does not persist past the current function invocation.

Basically, this.foo within a function is not equivalent to var foo within that same function. The first actually references a property value on the this object, whereas the second only references a local variable in the current function invocation scope.

Here's an example to illustrate this difference:

function myFunction(myArg) {
  console.log("this.foo = " + this.foo);
  console.log("foo = " + foo);
  var foo = "test";
  console.log("foo' = " + foo);
  var vm = this;
  console.log("vm.foo = " + this.foo);
  vm.foo = myArg;
  console.log("vm.foo' = " + this.foo);
}

console.log("window.foo = " + window.foo);
console.log(">>> Test call 1");
myFunction("abc");

console.log("window.foo = " + window.foo);

console.log(">>> Test call 2");
myFunction("xyz");

console.log("window.foo = " + window.foo);

For convenience, here is the console output:

window.foo = undefined
>>> Test call 1
this.foo = undefined
foo = undefined
foo' = test
vm.foo = undefined
vm.foo' = abc
window.foo = abc
>>> Test call 2
this.foo = abc
foo = undefined
foo' = test
vm.foo = abc
vm.foo' = xyz
window.foo = xyz

As you can see, this inside the function actually refers to the global window object. That means that the value of vm.foo that you assign inside the function is actually available anywhere that window is accessible (i.e., everywhere in your script). You can change what object is used as this if you invoke the function using its call method, and explicitly pass a different object as thisArg. You can also get a different object as this if you invoke the function as a method on some object. Here's an example illustrating both of these possibilities:

function myFunction(myArg) {
    console.log("this.foo = " + this.foo);
    console.log("foo = " + foo);
    var foo = "test";
    console.log("foo' = " + foo);
    var vm = this;
    console.log("vm.foo = " + this.foo);
    vm.foo = myArg;
    console.log("vm.foo' = " + this.foo);
}

var x = { f: myFunction };
var y = { f: myFunction, foo: "YYY" };
var z = { foo: "ZZZ" };

x.f("x"); // "this" is "x"
y.f("y"); // "this" is "y"
myFunction.call(z, "z"); // "this" is "z"

console.log("x.foo = " + x.foo);
console.log("y.foo = " + y.foo);
console.log("z.foo = " + z.foo);

Notice how the calls that use y and z for this have initial values of this.foo, since the corresponding objects are initialized with a value for the foo property. The value of this.foo persists in the object referenced by this, not in the function itself (unless of course this is referencing the function itself).

DaoWen
  • 32,589
  • 6
  • 74
  • 101
  • Keep in mind this means that the variable "foo" will also exist outside the function after the function is run. Try adding a `console.log(this.foo);` at the end of the above code. – IMTheNachoMan Jun 01 '16 at 14:40
  • That only "persists" because `this` in your example is the global object as the function is being executed with no execution context. If you do `new myFunction()`, `this` will refer to the new instance and the property will not be there in next call. Angularjs modules have their own execution context so `this` will not be the global object so it doesn't persist between new module instances – Patrick Evans Jun 01 '16 at 14:43
  • @PatrickEvans - I don't understand the point that you're trying to make. The value assigned to the property `foo` will persist with whatever object corresponds to `this`. If you do `new myFunction("123").foo`, you get the value `"123"`. If you do `var x = new myFunction("123"); myFunction.call(x, "ijk");`, then `x.foo` changes from `"123"` to `"ijk"`. – DaoWen Jun 01 '16 at 15:03
  • Yea the instance keeps the property, but the property does not persist across instances. Your example is misleading as it uses `this` making any new user who doesn't know better to think you are setting an instance property (when you're just setting a global property). If you do: `new myFunction("abc");` and then `new myFunction("xyz");` you do not get the same results, ie when you do `new myFunction("xyz")`, `this.foo` is not going to be `"abc"`. This is important because since OP is using AngularJS their controller function has its own context so `vm.foo` is not the same as `window.foo` – Patrick Evans Jun 01 '16 at 15:18
  • @PatrickEvans - I don't think that was unclear. I specifically said that `this` was referencing `window` in that case, but that it's possible to get `this` to reference something else. In any case, I've added another example to show that more clearly. – DaoWen Jun 01 '16 at 15:44
0

Inside a function, var foo = 'test' does not necessarily relate foo to this, because the value of this depends on how the function was called (see Function context).

Rather independently of the above, the reason for assigning this to vm is to keep its reference in case you want to have another function inside this function, where you refer to the original context of this. This is usually done within a controller function, see this Angular Style Guide.

idleherb
  • 1,072
  • 11
  • 23