I need to correct this code in order to make it increment on each click.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Clicker</title>
<meta name="description" content="">
<style></style>
</head>
<body>
<button>Click!</button>
<script>
const counter = {
cnt: 0,
inc: function() {
cnt++;
console.log(cnt);
}
};
const button = document.getElementsByTagName('button')[0];
button.addEventListener('click', counter.inc, false);
</script>
</body>
</html>
The solution I have right now works fine, but not sure what are the concepts behind it, the solution is :
inc: function() {
countert++;
console.log(countert);
}
I need to correct this code in order to make it increment on each click.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Clicker</title>
<meta name="description" content="">
<style></style>
</head>
<body>
<button>Click!</button>
<script>
const counter = {
cnt: 0,
inc: function() {
cnt++;
console.log(cnt);
}
};
const button = document.getElementsByTagName('button')[0];
button.addEventListener('click', counter.inc, false);
</script>
</body>
</html>
The solution I have right now works fine, but not sure what are the concepts behind it, the solution is :
inc: function() {
counter.cnt++;
console.log(counter.cnt);
}
Share
Improve this question
edited Dec 11, 2017 at 9:34
ChrisM
1,5866 gold badges22 silver badges29 bronze badges
asked Dec 11, 2017 at 9:17
Naveen DINUSHKANaveen DINUSHKA
1,6273 gold badges23 silver badges45 bronze badges
6
-
simply that
cnt++
is not incrementing the samecnt
insidecounter
, you need to increment that by doingcounter.cnt
. – gurvinder372 Commented Dec 11, 2017 at 9:19 - The concepts you are missing are basically concerned with scope: Which part of your code can see which variables. – Sirko Commented Dec 11, 2017 at 9:19
-
So your code is working with
counter.cnt
because there is no global variablecnt
onlycounter
has it. Is there any other issues? – Justinas Commented Dec 11, 2017 at 9:19 -
You need
counter.inc.bind(counter)
– Alnitak Commented Dec 11, 2017 at 9:19 - @Alnitak the bind(counter) what does this do? I actually have not written anything like that but it still works fine – Naveen DINUSHKA Commented Dec 11, 2017 at 9:29
5 Answers
Reset to default 8Its just a scoping
issue,
//Right approach would be,
const counter = {
cnt: 0,
inc: function() {
this.cnt++;
console.log(this.cnt);
}
};
Your erroring code will look for a variable cnt
declared in the current scope and traverse until the global one. It will throw error, if it doesn't find a reference.
Since you are passing the inc
as an event listener, you have to bind the scope for it, otherwise, the this
inside of that function will point to the element which triggers the event. Here in this case, the element would be a button
.
button.addEventListener('click', counter.inc.bind(counter), false);
Or the most readable approach would be,
button.addEventListener('click', function() {
counter.inc()
}, false);
Another reason for avoiding .bind
is, once if you bind a context to a function using .bind
. You cannot override the context of it after that. Even using .call/.apply
In the button.addEventListener()
call you need to use
either:
counter.inc.bind(counter)
or (since you appear to be using ES6)
() => counter.inc()
as the registered callback.
You also need to reference the correct cnt
(i.e. this.cnt
) within the inc
method.
The problem with your code is:
inc: function() {
cnt++;
console.log(cnt);
}
cnt will refer to a global variable, not the property of counter as you want. You need to set it using this.cnt++
.
The second things, is when you bind your addEventListener, it only passes the function, so this
context when the function is called, is not actually the counter. You need to change it to:
button.addEventListener('click', function() {
counter.inc();
}, false);
or button.addEventListener('click', () => counter.inc(), false);
or bind the counter.inc to counter like:
counter.inc = counter.inc.bind(counter);
Use this.cnt
to access the cnt
variable inside the function.
inc: function() {
this.cnt++;
console.log(this.cnt);
}
Also you need to bind the value of this
to counter
inside the function like this:
button.addEventListener('click', counter.inc.bind(counter), false);
Explaination:
Here we are providing a callback
function as the second argument to addEventListener
function. For this
inside this callback to be equal to the counter
object we are using bind
.
According to MDN Web Docs
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
Therefore the value of this
inside callback is set to counter
and we can access its property cnt
as this.cnt
.
The concept is that you are in is object literal, object literals encapsulate data, enclosing it in a tidy package, global This minimizes the use of global variables which can cause problems when bining code , in the first example you showed us you are retrieving global cnt variable and incrementing it which does'not exists in global scope, it is in counter scope, to retrieve it's properties and methods you need to call object first and then it's property like this object.(method or property)
inc: function() {
counter.cnt++;//same as
this.cnt++;//this
console.log(counter.cnt);
}