A Short Refactoring Road of Javascript
Seek and find.
Last month I was busy to test one of my idea that help people plan their daily trips easier, then I created a site called quickloop. However, curious friends may find the source code looks so ugly, definitely not object oriented nor unit testable. YES, that’s what we called prototype
.
As a guy always trying to cook better data, I started a simple refactoring three days ago. Since I am a classic layman of Javascript design pattern, I decide to read a little bit about the design pattern in Javascript. This book, Learning Javascript Design Patterns, is a very good source to quickly grasp the key concept and start your refactoring road. Something called prototype pattern
comes to my mind. Sounds interesting, let’s have a look at what it does.
Previously, a piece of my code looks like the following block.
1 | function getCurrentLocation() { |
This kind of code is a typical guy who learned Javascript for an hour could write. But why it does not a good code? Simply for two reason: 1) it does not look pretty; 2) it is not modulized which causes a lot of trouble to unit test. So how does this prototype pattern
could help? Let’s see what we could do to change the above code into a prototype pattern code.
1 | var MapServiceHelper = function () { |
Thereafter, we can use the MapServiceHelper in the following way.
1 | $(doucument).ready(function () { |
Now do you feel the code becomes more clear to understand and maintain? At least I do. However, if you look at the getCurrentLocation()
function, you will find the centerMapByPosition()
is actually a callback from Google Maps API. So can I just use this.centermapByPosition
as my callback?
Unfortunately, you cannot althougth I thought so and used that way. The key issue here is Javascript’s context. If you define a variable inside a Javascript function and this variable is visible from the callback function. In contrast, this
points to a different context when the execution jumps to the callback function.
A simple solution is to make a copy of the context to a variable so that the context can be exposed to the callback function.
1 | function A () { |
This looks like a good solution and it works well. But the only thing I don’t like is the duplicaltion. I have to make a copy of the context almost everywhere when I meet a callback function. Moreover, if you have multiple layer nested callback, this make life even worse. Thanks to the post, Understanding Scope and Context in Javascript, I could use an even better way which is referred as call and apply
. See the following code as an example.
1 | if(!('bind' in MapServiceHelper.prototype)){ |
In this way, I can use any callback funtion with a suffix .bind(this)
to force the context to the one I need. Finally, I change it to the following style.
1 | getCurrentLocation: function () { |
Till now, a short refactoring with the prototype pattern has been done and the code looks better. More importantly, it helps me quickly locate a bug that I could spend a long time to notice.