Reputation: 53
Confused about how increment
can change value
and that changed value
is accessible to getValue
, but not to a property of the same object.
Does this have to do with the fact that increment and getValue methods are inner functions of the anonymous function that value is defined in?
var myObject = function() {
var value = 0;
return {
increment: function(inc){
value += typeof inc === 'number' ? inc : 1;
},
getValue: function(){
return value;
},
value: value,
};
}();
console.log(myObject.getValue()); // 0
myObject.increment(2);
console.log(myObject.getValue()); // 2
console.log(myObject.value); // 0
myObject.increment(2);
console.log(myObject.getValue()); // 4
Upvotes: 0
Views: 381
Reputation: 943801
var foo
creates a variable that is scoped to the function it is declared with in. It can be accessed as foo
anywhere inside that function or another function declared inside the first function.
myObject.foo
creates a property that is attached to the object. It can be accessed as ???.foo
where ???
is a reference to the object that myObject
is a reference to. You can do this anywhere you can find a reference to the object.
Properties are not variables. Variables are not properties. (The exception is that global variables are properties of the global (window
in a browser) object.
When you create the object you said:
value: value,
But that copies the then current value of the value
variable to the value
property.
That is a number, which isn't a reference.
When you update the value
variable, the value
property is unchanged.
Upvotes: 3
Reputation: 51916
Other answers like @Quentin's have explained what the issue is pretty thoroughly. Here's a proper way by minimally modifying your current approach to correct the problem though:
var myObject = function() {
return {
increment: function(inc) {
this.value += typeof inc === 'number' ? inc : 1;
},
getValue: function() {
return this.value;
},
value: 0
};
}();
console.log(myObject.getValue()); // 0
myObject.increment(2);
console.log(myObject.getValue()); // 2
console.log(myObject.value); // 2
myObject.increment(2);
console.log(myObject.getValue()); // 4
console.log(myObject.value); // 4
However, this functionality would be a great example to make use of an ES6 class
:
class Counter {
constructor (value = 0) {
this.value = value
}
increment (amount = 1) {
this.value += amount
}
getValue () {
return this.value
}
}
let myObject = new Counter()
console.log(myObject.getValue()) // 0
myObject.increment(2)
console.log(myObject.getValue()) // 2
console.log(myObject.value) // 2
myObject.increment(2)
console.log(myObject.getValue()) // 4
console.log(myObject.value) // 4
As was pointed out in comments, the closure and getValue()
seem rather pointless. If you want to allow value
to access a scoped variable, and disable modifying it, you could implement it this way:
var myObject = function() {
var value = 0;
return {
increment: function(inc) {
value += typeof inc === 'number' ? inc : 1;
},
getValue: function() {
return value;
},
get value() {
return value;
},
// disable setting it without throwing
set value(newValue) {
return value;
}
};
}();
console.log(myObject.getValue()); // 0
myObject.increment(2);
console.log(myObject.getValue()); // 2
console.log(myObject.value); // 2
// won't work
myObject.value = 4
// still 2
console.log(myObject.getValue()); // 2
console.log(myObject.value); // 2
Upvotes: 2