I've finally gotten around to learning Lisp/functional programming. However, what I've noticed is that I'm trying to bring ideas back into JavaScript.
Example
Before
var myPlacemark,
myLineString;
myLineString = ge.createLineString('');
myLineString.setLatitude(100);
myLineString.setLongitude(-100);
myPlacemark = ge.createPlacemark('');
myPlacemark.setGeometry(placemark);
After
var myPlacemark;
myPlacemark = (function(point, placemark){
point.setLatitude(100);
point.setLongitude(-100);
placemark.setGeometry(point);
return placemark;
})(ge.createPoint(''), ge.createPlacemark(''));
Is there any reason I shoudn't be doing it the 2nd way?
3 Answers 3
What you have there is actually just a fancy assignment operation. The closure there plays no role. And if you would need to set another placemark, you would have to repeat the code or wrap in one more function.
IMHO, it would be much more pragmatic to use a lot simpler approach:
var createPlacemark = function (point, placemark) {
point.setLatitude(100);
point.setLongitude(-100);
placemark.setGeometry(point);
return placemark;
},
myPlacemark = createPlacemark(ge.createPoint(''), ge.createPlacemark(''));
This way you get reusable routine with a clear name. And if goal of this all was to prevent external sources from adding placemarks, just warp it all in the standard:
(function () {
}());
The bottom line is: you were over-thinking it.
-
\$\begingroup\$ I'm aware that it's not exactly helping my code readability. My question was more so regarding the performance penalties that might result from going 'closure crazy'. \$\endgroup\$ilia choly– ilia choly2012年09月11日 04:21:11 +00:00Commented Sep 11, 2012 at 4:21
-
\$\begingroup\$ In your example there would be no performance penalty. The processing costs for closures are negligible. What you have to worry about sometimes is the memory leaks. You can end up binding variables with large amount of data (common mistake in dealing with XHR), which is never garbage-collected. But that does not seem possible in your situation. \$\endgroup\$tereško– tereško2012年09月11日 04:38:36 +00:00Commented Sep 11, 2012 at 4:38
-
\$\begingroup\$ I tend to agree with what you're saying @teresko, except for 1 thing: if the OP doesn't wrap the lot in a function, there is one more global being created in the first version, and that's one too many IMO \$\endgroup\$Elias Van Ootegem– Elias Van Ootegem2012年09月11日 20:50:49 +00:00Commented Sep 11, 2012 at 20:50
-
\$\begingroup\$ If you are referring to
createPlacemark
, then it is just a different way of defining function. But if you are talking aboutmyPlacemark
not havingvar
in front of it, then you missed the comma in previous line. Basically, I do not get what you meant with the "one more global". \$\endgroup\$tereško– tereško2012年09月11日 21:12:12 +00:00Commented Sep 11, 2012 at 21:12 -
\$\begingroup\$ @tereško The scope of
myLineString
is global. The scope ofpoint
is the function. So in the second example the global variablemyLineString
doesn't exist. \$\endgroup\$James Khoury– James Khoury2012年09月12日 03:06:45 +00:00Commented Sep 12, 2012 at 3:06
While using a closure to prevent polluting the global namespace is a good idea, you shouldn't be passing in random data like that. The way you are doing it, you are forcing the reader to scroll to the bottom of the function call before reading the function body - that's just plain confusing for no good reason.
Instead, declare the variables regularly within the closure, and assign their values right then and there. That way, it's much easier to read (and maintain), while still keeping the global namespace intact.
In addition, Crockford suggests that you put the calling parentheses inside the wrapping parenthesis.
With all that in mind, here's your code, refactored:
var myPlacemark = (function() {
var point = ge.createPoint(''),
placemark = ge.createPlacemark('');
point.setLatitude(100);
point.setLongitude(-100);
placemark.setGeometry(point);
return placemark;
}());
-
\$\begingroup\$ Plus this would finally become a real closure, not just a function object, since it closes over the
ge
from the outer scope. Strangely enough, this namespace pollution prevention is easier in java using simple nested block{}
, since it creates a sub-scope – in javascript it doesn't. \$\endgroup\$charlie– charlie2012年09月21日 09:55:11 +00:00Commented Sep 21, 2012 at 9:55
It would be a real closure only if you had done one of the following:
function createPlacemark(placemark, point, latitude, longitude) {
point.setLatitude(latitude);
point.setLongitude(longitude);
placemark.setGeometry(point);
return placemark;
}
function closure1(point, placemark) {
return function(latitude, longitude) {
return createPlacemark(placemark, point, latitude, longitude);
};
}
function closure2(latitude, longitude) {
return function(point, placemark) {
return createPlacemark(placemark, point, latitude, longitude);
};
}
var myPlacemark1 = closure1(ge.createPoint(''), ge.createPlacemark(''))(100, 100);
var myPlacemark2 = closure2(100, 100)(ge.createPoint(''), ge.createPlacemark(''));
i.e. capture context variables in a closure. A function object is not necessarily a closure.