Ever wondered why setting array.length = 0
makes an array empty or array.length = 'some string'
throws exception ?
Code example.
So now you have curiosity to know what happens in the background when command array.length = 0
takes place ?
Let's start this journey with below requirement.
Create an object circle
with properties area
& radius
, perform basic validations while assigning value to radius
property and calculate area
automatically.
Formula of area is = PI * radius * radius; value of PI is 3.14
By reading this requirement what we think first is to create below getters and setters methods to an object circle
1) getRadius()
2) setRadius(radius)
3) getArea()
We will use following helper method to validate radius
property.
function isANumber(num) {
return typeof num === 'number'
}
Typical implementation will be like below
circle = {
radius: 0,
area: 0,
getRadius() {
return this.radius
},
getArea() {
return this.area
},
setRadius(r) {
if (!isANumber(r)) {
throw('Invalid radius passed to setRadius()');
} else {
this.radius = r;
this.area = 3.14 * r * r;
}
}
}
Tests
circle.getRadius() // 0
circle.getArea() // 0
circle.setRadius(10);
circle.getRadius(); // 10
circle.getArea(); // 314
circle.setRadius('abc'); // 'Invalid radius passed to setRadius()'
circle.getRadius(); // 10
circle.getArea(); // 314
Are we done ?
It seems yes by looking @ output of test cases - as all went as expected.
Wait... wait... wait.... but did you find any problem here ?? There are actually.
-
This approach is not scalable - think when there are multiple properties on which you need to make validation before updating ? code will really big & ugly.
-
You need to remember all method names (getters and setters).
(Even if you don't find any problem in above approach then there is no harm in knowing other alternative way - later we can decide when to use what ?)
In situation like above one javascript's in house getters and setters can be used.
It is as simple as -
- When you assign value to property - it's setter will be called internally.
- When you access (read) property - it's getter will be called internally.
Example.
circle = {
_radius: 0,
_area: 0,
get radius() {
return this._radius
},
get area() {
return this._area
},
set radius(r) {
if (!isANumber(r)) {
throw('Invalid radius');
} else {
this._radius = r;
this._area = 3.14 * r * r;
}
}
}
Note
You can not return same key from it's getter() , that is why we are returning _radius
from get radius()
.
I know right now you have curiosity to know what happen if we do that - don't worry it is covered @ end of this doc.
You may think that above code is complex and a bit boring as well, but actual benefit you will see in accessing or modifying values (radius & area) - no more method calls like older approach - see code below.
Tests
/* initial values */
circle.radius; // 0
circle.area; // 0
/* setting radius to 10 */
circle.radius = 10;
/* getting radius and area */
circle.radius; // 10
circle.area; // 314
/* setting invalid value */
circle.radius = 'abc'; 'Invalid radius'
/* getting radius and area after trying to set invalid values to radius */
circle.radius; // 10
circle.area; // 314
You can use Object.defineProperty to make code cleaner.
circle = {
_radius: 0,
_area: 0
}
Object.defineProperty(circle, 'radius', {
get: function() {
return this._radius
},
set: function(r) {
if (!isANumber(r)) {
throw('Invalid radius');
} else {
this._radius = r;
this._area = 3.14 * r * r;
}
}
});
Object.defineProperty(circle, 'area', {
get: function() {
return this._area
}
});
You can perform modification on one or more member of an object from setter of other member(s). (Like example of an array given @ beginning)
When you return same key from it's getter - infinite calls to getter() will take place and eventually you will get RangeError: Maximum call stack size exceeded
Now you can understand that what happens when you set array.length = n
, if n
is less than length
of an array than all the values whose index is greater or equal to n
will be removed from an array and array.length
will be set to n
, on the other side if n
is greater than actual length
then remaining indexes in array will be filled with empty
More on this operations, you can read here
So craft your getters and setters carefully, not all the places you will need such getters and setters - think twice and cut once.
More on getters, setters & Object.defineProperty.
Learned from internal tech talks in my company Tekion Corp.
Thanks to my mentor (& presenter of this topic) : Nitish Kumar