Once again I found JavaScript code on the Internet that contains an inline function where, in my opinion, regular statements would make just as much sense. Here's the first sample:
function outerHTML(node){
// if IE, Chrome take the internal method otherwise build one
return node.outerHTML || (
function(n) {
var div = document.createElement('div'), h;
div.appendChild(n.cloneNode(true));
h = div.innerHTML;
div = null;
return h;
})(node);
}
If you'd ask me to code the same thing, it would look like this:
function outerHTML(node){
var div, h;
// if IE, Chrome take the internal method otherwise build one
if (node.outerHTML) {
return node.outerHTML;
}
div = document.createElement('div')
div.appendChild(node.cloneNode(true));
h = div.innerHTML;
div = null;
return h;
}
EDIT: As OverZealous stated, there is a difference in logic on this one. I leave it here so nobody gets confused about that answer.
And maybe another original sample (yes, this doesn't "compile" as it's just a code fragment):
addGetters: function (attributes) {
var that = this;
function addGetter(attr) {
that.prototype["get" + attr.capitalize()] = function() { return this[attr]; };
}
for(var i = 0; i < attributes.length; i++) {
var attr = attributes[i];
addGetter(attr);
}
},
compared to my attempt
addGetters: function (attributes) {
for(var i = 0; i < attributes.length; i++) {
var attr = attributes[i];
this.prototype["get" + attr.capitalize()] = function() { return this[attr]; };
}
},
Is there a difference? Doesn't the original version consume more space since a function needs to be created and/or isn't it slower because of this? Is there a possible memory leak?
The utilisation of CPU and memory is very important as I'm coding in an environment where both are limited and any "less" is good. And since there's no sizeof() in JavaScript and its implementation attempts aren't safe to interpret any thinking-ahead-fixes are important.
Please note that as far as the "my version" is concerned I didn't test it. I'm just trying to explain what I'm trying to ask.
EDIT: Even though this question has an answer, I'm still wondering about the memory utilisation. If somebody has some insights, please don't hesitate to add it here.
For the first one, I don't believe there is any reason for the function. It might have (d)evolved into that state through small changes, but the extra function wrapper isn't providing any benefit that I can see.
The second example, however, is actually critical to use the function wrapper. The reason is due to JavaScript's (sometimes frustrating) function-level scope. In your example, there is only one attr variable. It is shared across the different attributes. This means that, in the end, every attribute will return the value of last attribute in the array.
e.g:
var attrs = ['foo', 'bar', 'baz']
obj.addGetters(attrs);
obj.getFoo(); // returns obj.baz
obj.getBar(); // returns obj.baz
By wrapping the getter creation in a function, you eliminate that issue, because attr ends up being scoped to the creating function. This is why Douglas Crockford's JSLint says "Don't create a function inside a loop". It leads to unexpected bugs like that one.
As OverZealous pointed out, one needs to be sure about the logic that's happening. +1 for that.
As far as the performance is concerned I finally had the time to do some testing on my own. However, I'm working in an environment where I can't really check memory utilisation. So I tried to fool around with the performance.
The result is that it may have an impact depending on how often this feature is used. On my target system the simple creation of an inline function that does close to nothing, e.g.
myArray.each(function inlineFunc(el) { return el; });
takes about 1.8 seconds for 10,000 creations of such a function (in the example above myArray had no elements). Just in comparison the PC-version of that browser needs 1,000,000 iterations to get somewhere close to that (obviously this also depends on the hardware).
Since the 10,000 iterations are reached in the code we use (not directly in one loop, but functions are created all over the code), we will have a word with our subcontractor.
The answer lies in the eye of the beholder.
It's a matter of preference.
It's up to you if you put "speed" above modularity.
Ask yourself this: why do you use a for when it can be done with a while? It is proven that in some cases the while structure is a bit faster.
Related
So I'm working on a sort of JavaScript framework, just some utility things for myself to use in future projects, and I want to make a data binding system.
The first method I used was objects, and the code would just loop through the specified html element and look for occurences of {{key}} in the markup and then look for that key in the object and replace it that way in the HTML.
For example, if you had <div>{{name}} is a cool guy</div> in the HTML and had {name:"joseph"} in the JS then the final product would be displayed on screen as 'joseph is a cool guy'.
However, I decided later to change my method and instead the framework would except a function. So instead of {name:"joseph"} you would give it function(){ var name = "joseph" }.
This obviously looks better and gives a lot better functionality.
I changed the processing function so instead of looking for the key/value pair to replace the {{key}}, it just uses eval on the variable to gets its value.
My problem lies here: How do I run my search/replace code INSIDE the scope of the function the user passes.
If the user defines variables within that function, their values will not be available anywhere else due to scope issues.
I've tried using Function.toString() to actually modify the source code of the function, but nothing's working and it's all very complicated.
(The issues are not due to the actual solution, I think that Function.toString() might work, but due to my implementation. I keep getting errors)
So... What is the best way to run arbitrary code in the scope of another function?
Critera:
Obviously, I can't modify the function because the user is passing it in. (you can't just tell me to add the search/replace code to the bottom of the function)
The variables must stay in the local scope of the function. (no cheating by using window.name = "joseph" or anything)
I am also aware of how terrible eval is so any suggestions as to get it to work are greatly appreciated. Thanks!
Code:
function process(html) {
var vars = html.match( /({{)[^{}]*(}})/g )
// vars = ['{{variable}}', '{{anotherVariable}}']
var names = vars.map( function(x){ return x.replace("{{", "").replace("}}", "") } )
// names = ['variable', 'anotherVariable]
obj = {}
for (var i = 0; i < names.length; i++) {
obj[names[i]] = eval(names[i])
}
for (var p in obj) {
html = html.replace(new RegExp('{{'+p+'}}','g'), obj[p]);
}
return html
}
You should go back to your first method with the object, it's much better. You can still pass a function, but the function should return an object:
function () {
return { name: 'joseph' }
}
I'm currently using JsHint and am receiving warning W083: "Don't make functions within a loop". I read this post from JsLint Error Explanations and understand why you should not do this, which essentially boils down to the asychrnonous nature of JavaScript and the potential for variables to be overwritten.
However, I also read in a few other posts here on SO that although this is a faux pas it does not always lead to bugs depending on the situation.
My situation in particular that JsHint is complaining about is a for-loop that uses the jQuery $(selector).each() function within it. This function takes a function as a parameter. Below is a snippet of the code that I'm concerned about. Don't worry about what it actually does+ since I'm really just using this as an example:
for (var i = 0; i < sections.length; i++) {
disableSectionState[sections[i].name] = {};
$('.' + sections[i].name).each(function (index, element) {
var id = $(element).attr('id');
disableSectionState[sections[i].name][id] = $(element).attr('disabled');
});
if (sections[i].isChecked) {
$('.' + sections[i].name).attr('disabled', 'disabled');
}
}
Essentially, this is just a nested for-each loop within a for-loop, so I didn't think this would be too dangerous, but I'm obviously not familiar with all of the quirks in js.
As of right now, everything is working properly with this function in particular, but I wanted to ask the community about the dangers of this using jQuery's each function within a loop.
To prevent this being marked as a dupe I did see this SO question, but the only answer doesn't go into any detail or explain anything, and based on the comments it looks like an XY problem anyway. I'm more interested in the why this is when at it's core is that it's essentially a nested loop.
Is it really that much safer for this function to be extracted and named outside of the loop? If I copied the loop counter to a variable in scope of the anonymous function, would that eliminate the potential danger of this design? Is that function executed completely asynchronously outside of the main for-loop?
+In case you're actually interested: This code is used to determine if certain fields should be disabled at page load if certain options are enabled.
The problem isn't using jQuery's each within the loop, it's repeatedly declaring a function. That can lead to some odd closure issues (the function closes on a reference to the loop counter, which still gets updated and can change) and can be a non-trivial performance problem on less clever VMs.
All JSHint is asking you to change is:
function doStuff(index, element) {
var id = $(element).attr('id');
disableSectionState[sections[i].name][id] = $(element).attr('disabled');
}
for (var i = 0; i < sections.length; i++) {
disableSectionState[sections[i].name] = {};
$('.' + sections[i].name).each(doStuff);
if (sections[i].isChecked) {
$('.' + sections[i].name).attr('disabled', 'disabled');
}
}
Most of the dangers come when you're calling something asynchronously from within a loop and close over the loop counter. Take, for example:
for (var i = 0; i < urls.length; ++i) {
$.ajax(urls[i], {success: function () {
console.log(urls[i]);
});
}
You may think it will log each URL as the requests succeed, but since i probably hit length before any requests have come back from the server, you're more likely to see the last URL repeatedly. It makes sense if you think about it, but can be a subtle bug if you aren't paying close attention to closure or have a more complex callback.
Not declaring functions within the loop forces you to explicitly bind or pass the loop counter, among other variables, and prevents this sort of thing from accidentally cropping up.
In some more naive implementations, the machine may also actually create a closure scope for the function every iteration of the loop, to avoid any potential oddities with variables that change within the loop. That can cause a lot of unnecessary scopes, which will have performance and memory implications.
JSHint is a very opinion-based syntax checker. It's kind of like deciding which type of citations to do on a paper MLA or APA. If you go with one, you just follow their rules because, most of the time, it is "right", but it's rarely ever wrong. JSHint also says to always use === but there may be cases to use == instead.
You can either follow the rules or ignore them with the following
// Code here will be linted with JSHint.
/* jshint ignore:start */
// Code here will be ignored by JSHint.
/* jshint ignore:end */
If you are going to use JSHint, I would just comply. It tends to keep the code a little more consistent, and when you start trying to work around one warning or error, it tends to start creating a bunch more
Is it really that much safer for this function to be extracted and named outside of the loop?
In practice, yes. In general, on case by case, maybe not.
If I copied the loop counter to a variable in scope of the anonymous function, would that eliminate the potential danger of this design?
No.
Is that function executed completely asynchronously outside of the main for-loop?
Pretty sure it is.
I am working on making all of our JS code pass through jslint, sometimes with a lot of tweaking with the options to get legacy code pass for now on with the intention to fix it properly later.
There is one thing that jslint complains about that I do not have a workround for. That is when using constructs like this, we get the error 'Don't make functions within a loop.'
for (prop in newObject) {
// Check if we're overwriting an existing function
if (typeof newObject[prop] === "function" && typeof _super[prop] === "function" &&
fnTest.test(newObject[prop])) {
prototype[prop] = (function(name, func) {
return function() {
var result, old_super;
old_super = this._super;
this._super = _super[name];
result = func.apply(this, arguments);
this._super = old_super;
return result;
};
})(prop, newObject[prop]);
}
}
This loop is part of a JS implementation of classical inheritance where classes that extend existing classes retain the super property of the extended class when invoking a member of the extended class.
Just to clarify, the implementation above is inspired by this blog post by John Resig.
But we also have other instances of functions created within a loop.
The only workaround so far is to exclude these JS files from jslint, but we would like to use jslint for code validation and syntax checking as part of our continuous integration and build workflow.
Is there a better way to implement functionality like this or is there a way to tweak code like this through jslint?
Douglas Crockford has a new idiomatic way of achieving the above - his old technique was to use an inner function to bind the variables, but the new technique uses a function maker. See slide 74 in the slides to his "Function the Ultimate" talk. [This slideshare no longer exists]
For the lazy, here is the code:
function make_handler(div_id) {
return function () {
alert(div_id);
};
}
for (i ...) {
div_id = divs[i].id;
divs[i].onclick = make_handler(div_id);
}
(I just stumbled on this questions many months after it was posted...)
If you make a function in a loop, an instance of a function is created for each iteration of the loop. Unless the function that is being made is in fact different for each iteration, then use the method of putting the function generator outside the loop -- doing so isn't just Crockery, it lets others who read your code know that this was your intent.
If the function is actually the same function being assigned to different values in an iteration (or objects produced in an iteration), then instead you need to assign the function to a named variable, and use that singular instance of the function in assignment within the loop:
handler = function (div_id) {
return function() { alert(div_id); }
}
for (i ...) {
div_id = divs[i].id;
divs[i].onclick = handler(div_id);
}
Greater commentary/discussion about this was made by others smarter than me when I posed a similar question here on Stack Overflow:
JSlint error 'Don't make functions within a loop.' leads to question about Javascript itself
As for JSLint:
Yes, it is dogmatic and idiomatic. That said, it is usually "right" -- I discover that many many people who vocalize negatively about JSLint actually don't understand (the subtleties of) Javascript, which are many and obtuse.
Literally, get around the problem by doing the following:
Create a .jshintrc file
Add the following line to your .jshintrc file
{"loopfunc" : true, // tolerate functions being defined in loops }
JSLint is only a guide, you don't always have to adhere to the rules. The thing is, you're not creating functions in a loop in the sense that it's referring to. You only create your classes once in your application, not over and over again.
If you are using JQuery, you might want to do something like this in a loop:
for (var i = 0; i < 100; i++) {
$("#button").click(function() {
alert(i);
});
}
To satisfy JSLint, one way to work around this is (in JQuery 1.4.3+) to use the additional handler data argument to .click():
function new_function(e) {
var data = e.data; // from handler
alert(data); // do whatever
}
for (var i = 0; i < 100; i++) {
$("#button").click(i, new_function);
}
Just move your:
(function (name, func) {...})()
block out of the loop and assign it to a variable, like:
var makeFn = function(name, func){...};
Then in the loop have:
prototype[prop] = makeFn(...)
Yeah, read properly. In the last time I saw different patterns of argument validation in JavaScript (functions) and wondered which of them would be best-practice. At first I'll show two example code snippets. The first shows an (in my words) "immediate" argument/condition validation and the second one a "delayed" validation. Each of them affect the appearance of following code in different ways. Up to now I always used the "immediate" validation. But slowly I am getting doubtful if it's reasonable to force the whole following code into such conditional blocks. Please tell me what you think and what might be the "best" pattern.
And what about the place where variables are declared? A few times I read, that ALL variables should be declared on to of the method, before they're actually used. Is this correct? Because I think that it is useless to declare variables before it is sure that they'll be actually used (maybe invalid arguments force the throw of an Exception), I moved the variable-declaration-part beyond the argument/condition validation part. Is this advisable?
Thanks!
First example:
if ( colorStops.constructor === Array
&& colorStops.length
&& colorStops.every(function(c) {
return c instanceof ColorStop
}))
{
var privateVar1 = "foo",
privateVar2 = "bar",
privateVar3 = "tutifrutti";
// here goes the code
}
else {
throw new TypeError("GradientCanvasFacade: cannot add Colors; " +
"invalid arguments received");
}
Second example:
if (cg instanceof ColorGradient) {
throw new TypeError("PresetManager: Cannot add preset; " +
"invalid arguments received");
}
var privateVar1 = "foo",
privateVar2 = "bar",
privateVar3 = "tutifrutti";
// here goes the code
// Here goes the code that get executed when no explicit
// return took place ==> all preconditions fulfilled
Since JavaScript variables are scoped to the declaring function and not to the block as most other languages, declaring variables at the beginning of the function makes alot of sense.
function someFunc()
{
if (1==1)
{
var x = 1;
}
else
{
var x = 2;
}
return x
}
Now imagine a function a lot more complex, to me atleast, declaring x at the beginning makes alot of sense. For variables generally bound to a block (like iterator variables or collections) I still declare them in the block though.
I would definitely go for your second example not because it fails earlier, because really it doesn't, but because it's easier to remove and add validations this way without breaking a complicated if structure.
I'd go with the second, simply because it's easier to read. Also, with the first, if your function is very long, someone looking at the bottom, will wonder what that } is for, and have to hop up to the top to see.
Also the scoping of variables is very clear, even for someone who forgets that javascript has weird scoping rules.
Also, as mentioned by Martijn, the second method makes it a lot easier to check for various errors, ie each can have their own if statement and so on.
if (some condition) {
if (some other condition based in the first) {
if (another condition based in 1st and 2nd) {
do_job();
} else?
} else?
} else?
Where to put the else block? After every if or after the last?
It seems absolutely more readable the second choise
I've been programming for the Web for quite some time now, but have only just recently discovered a few new intricacies regarding the use of functions and the weird (or so I view them as) things you can do with them. However, they seem at this point only to be syntactically pretty things. I was hoping somebody might enlighten me as to how some of these newly discovered aspects could prove to be useful.
For example, the first time I ran this, I thought for sure it would not work:
<script>
function x(q)
{
q(x);
}
x(function(a)
{
alert(a);
}
);
</script>
But it did! Somehow, creating a named function which receives a different, anonymous function as its only parameter and then runs the function passed to it with itself passed as the parameter to it works just fine. This positively blew my mind and I'm almost certain there's a vast amount of practicality to it, but I just can't quite place it yet.
Ah, and another thing I was elated to discover: using a globally scoped variable to store a function, one can later in the execution use JavaScript's eval() function to modify that variable, thus changing the function's inner workings dynamically. An example:
<script>
var f = function()
{
alert('old text');
}
eval('f = ' + f.toString().replace('old text', 'new text'));
f();
</script>
Sure enough, that code alerts the "new text" string; when I saw that, my mind was once again blown, but also immediately intrigued as to the potential to create something incredible.
So... my burning question for Stack Overflow: how can such seemingly abstract coding principles be used in any positive way?
What you're basically asking is How can I use functions as first-class objects?
The biggest and most common usage is closures (or anonymous functions) for event handling. However, just because you can be clever, it doesn't mean you should. Write clear, readable code just as you would in any other language.
Oh, and flog yourself for typing eval and never think about doing it again
The first one, closures, are very common in javascript. If you want some more advanced examples, here's a nice interactive playground you can mess with: http://ejohn.org/apps/learn/.
Here's my window.onload function I use when whatever I'm working on doesn't require a full blown library.
//add events to occur on page load
window.addOnload = function(fn) {
if (window.onload) {
var old = window.onload;
window.onload = function() {
old();
fn();
}
} else {
window.onload = fn;
}
}
Then whenever I need something to happen onload, I can just use an anonymous function. Here's an example from a recent maintenance project of mine.
//make all menu items have a hover property
window.addOnload(function(){
var cells = document.getElementsByTagName('td');
for (var i=0; i < cells.length; i++) {
if (cells[i].className != 'NavMenuItem') continue;
(function(cell){
cell.onmouseover = function() {
cell.className = 'NavMenuItemHighlight';
}
cell.onmouseout = function() {
cell.className = 'NavMenuItem';
}
})(cells[i])
}
});
As for your second 'discovery', just pretend you never found out about it.
Well, the first one is typically how you prove that the Halting Problem is undecidable...
Whether or not you consider that "useful" is entirely up to you, I guess B-)