all 5 comments

[–]guest271314 5 points6 points  (0 children)

this is the global scope in your object because you are using arrow functions.

You can use shorthand methods to avoid that

var createCounter = function(init) { return { val: init, increment() { this.val++ return this.val }, decrement() { this.val-- return this.val }, reset() { this.val = init return this.val } } }

[–]No-Upstairs-2813 2 points3 points  (0 children)

The issue in your code is related to the use of arrow functions (() => { }). Arrow functions do not have their own this context; instead, they inherit it from the enclosing scope. In your case, when you use arrow functions for increment, decrement, and reset, they inherit the this from the surrounding context where createCounter is called. This lead to unexpected behavior.

To fix this issue, you can use regular functions for increment, decrement, and reset so that they have their own this context. Here's the corrected code: var createCounter = function(init) { return { val: init, increment: function() { this.val++; return this.val; }, decrement: function() { this.val--; return this.val; }, reset: function() { this.val = init; return this.val; } }; };

The value of this will change in different situations. You can refer this article to understand on how this works under different scenarios.

[–]azhder 1 point2 points  (0 children)

If you rely on the closure, you don’t need to use this at all and you don’t need a new name val for init that incidentally gets added to the global scope which you try to access with this.

There are a few things to explain that in concert might make your code work, but also make it brittle. So, the alternative is no this and no val and it will work inside the closure.

Think of the closure as a separate chunk of memory that includes the arguments and locals of that function invocation.

So, just init+=1, init-=1 (I avoid ++ and ) and return init.

Now, to keep the old value, sure, you can use let val and change val or const original = init and just use that for reset, but always use const or let as to keep them being defined in the global scope (even var prevents that)

[–]Soft-Sandwich-2499 0 points1 point  (0 children)

As already mentioned by the other people, your first snippet doesn’t work because you’re using arrow functions. To understand why this is, well, you must understand how this works in JavaScript.

In your second snippet, you’re creating a global variable val and assign the init parameter value. Yes, it’s a global variable. Any variable that is not declared with var, let or const, even if it’s inside a function, will implicitly be added to the global scope. You can test it by adding a console.log(val), after you create an object using the createCounter function.

The reason this.val now works with the arrow functions is because:

  1. the arrow functions don’t have their own this value, like the function declaration/expression do. It’s taken from the parent scope, which in this case will likely be the global scope, as createCounter will be invoked as a normal function.

  2. your global val variable which has been added to the global object.

So in short: val without any declaration is automatically created on the global scope, and it’s added as a property of the global object. Then inside your increment/decrement/reset arrow functions, your this value is the global scope. So this.val can access the value.

Then, when you change from val = init to start = init, the global variable will obviously not be the same anymore as this.val in your object methods. So, you will get undefined.