I'm currently use jquery 1.8.3. I think it added indexOf to Array.prototype so now every of my array always contains the method indexOf as the first element.
Doing for (var i in object) I always get the method infexOf as my first element and it bugged my code.
Bug happened on IE8 only.
What I want is to remove this indexOf from all arrays or anyway to hack jquery / resolve this problem.
PS: I'm not even sure if it's jquery is the cause of this problem
Thanks.
Aside from not using for...in to iterate over an array, if you must use for...in, then combine it with hasOwnProperty to tell if the property you are looking at really belongs to the object in question, or came from the prototype:
for (var prop in myObject) {
if (myObject.hasOwnProperty(prop)) {
// this didn't come from the prototype.
}
}
The correct answer here is that you shouldn't be using a for(...in...) loop to iterate an Array in Javascript.
The whole point of having an Array is that it has a numbered sequence of elements, so you should be using a for() loop.
for(var i=0; i<myArray.length; i++) {
//do stuff here with myArray[i]
}
That alone will resolve the issue in this case, because it will only iterate the numbered elements, so the indexOf method won't get involved.
However, a brief explaination of the problem with for(..in..) here may be helpful, so let me explain...
The underlying cause of the error you're seeing is because the indexOf method isn't supported for arrays in IE8, so something in your code (not jQuery though) has added it to the Array prototype.
This in turn means that when you do a for(..in..) loop, it will be picked up as one of the elements to be iterated.
In this case, you have a better solution (the for() loop; see above), but in cases where you really do need to use a for(..in..) loop, this can be a real problem. You can prevent this by checking hasOwnProperty() immediately inside your for(..in..) loop. This function returns false for items that are part of the object prototype, so it helps you avoid hitting unwanted methods when looping an object.
This is considered best practice for every for(..in..) loop. In fact, if you use a tool like JSLint, to check your coding style, it will complain if you don't do this.
Related
In the last year I've been using array methods like map and filter more often instead of the standard for loop on an array. It feels simpler to read and write, and does all the things I'm most likely going to do anyway, like create a local variable.
Often times I don't return anything though. Eslint doesn't like me very much though. According to them, they say you always need a return, otherwise its "probably a mistake"
https://eslint.org/docs/rules/array-callback-return
Why? Is just good practice? What are downsides of a return-less array method?
Been thinking on this for a while. Any insight or thoughts would be great.
Should I use array methods like map and filter, if I'm not going to return anything?
No, you should not.
Why? Is just good practice?
Yes. It is a good practice to use the appropriate iteration method for the type of iteration you are doing. There are numerous ways to iterate for a reason. Pick the appropriate mechanism.
What are downsides of a return-less array method?
Using .map() and .filter() without actually returning anything from the callback have the following downsides:
Your code is misleading. The point of .map() and .filter() is to iterate over the array and produce a new array. When a developer reads some code and sees .map() or .filter() being used, they expect that there should be a returned array. When they don't see it being done that way, they will be confused, will initially feel like they don't understand the code. If I were doing a code review on code like this, I would not approve of code like this.
Your code unnecessarily creates objects that are not used. That's just wasteful and is not a good practice. Instead, use an iteration method that does not produce an output array such as for/of, a regular for loop or .forEach().
Your code won't lint. Linters provide objections to things for a reason. Using .map() or .filter() without returning anything from the callback is, just as the linter says, "probably a programming mistake" because that is not how those functions are designed to be used and there are appropriate alternatives when you don't want a returned array.
So, if you're just trying to do an iteration without creating any resulting array, use for/of or .forEach() or some other iteration scheme that isn't specifically designed to create an output array that you don't want.
First you need to know about the difference between Map/Filter and forEach.
resuming.. forEach is mostly used when you want iterate an array with/as a procedure. check
Map and Filter are related to a callback function applied on every iteration.
The return statement of those is what is going to be evaluated, not the function By the Map/Filter function at the end. Reason why it's needed. Althought JS allows "whatever" And of course you are able to define that function what comes to our understanding as "The filter".
For Filter you can see that "true" and "false" as when the "data" is going to be filtered or not.
basically you can loop with map or forEach/for, the difference are the following:
foreach: This iterates over a list and applies some operation with side effects to each list member, this means that you are transforming THE CURRENT ARRAY you are looping.... or as noticed by #TiagoCoelho, you dont mess with the array at all, just loop thought it.
map: This iterates over a list, transforms each member of that list, and returns another list of the same size with the transformed members, this means that you will get a BRAND NEW ARRAY with the modified items and you will also have in memory your old array.
so basically it depends on what you want to do with the data inside of your array.
References
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
examples:
var a = [1, 2, 3, 4];
var b = [1, 2, 3, 4];
//multiply each item for 2, it will stay on the same array.
a.forEach(i => {
i = i * 2
})
//multiply the items of B for 2 but it will return a new array
var c = b.map(i => {
return i * 2
})
console.log(a); //modified reference
console.log(b); //stays the same
console.log(c); //new array
I have been wonder where a for loop or a for..in loop would be farther on an array.
I have tested this using jsperf.
My For Loop had 16,676,377 op/s
while the for..in only had 519,853 op/s
So why is:
var a = ["hi", "hi2", "bye", "bye2"];
for (var i in a) {
return a[i];
}
Slower compared to:
var a = ["hi", "hi2", "bye", "bye2"];
for (var i = 0; i < a.length; i++) {
return a[i];
}
The answer for your question is simple: for in loop was not created to deal with arrays and does additional things as well and should not be used.
The main purpose of the for-in statement is to iterate thought object's properties, not through the array. This statement will also go into the array prototype chain, iteration through inherited properties and I think you do not need this or even do not know about this.
Another funny thing that you even do not know in what order it will be iterated.
So the main thing to remember - do not use for in with arrays. Only with objects.
P.S as RobG correctly added:
A for loop will search for properties on the [[Prototype]] chain too if they aren't found on the array. E.g. a for loop over [0,,2] will search for 1 all the way to Object.prototype[[Prototype]]
There are a couple of things wrong here.
your return in the loop's body causes the loop to abort after the first iteration, your tests are useless
for..in loops over an object's properties, an array's elements are not its only properties! were you to add a property, such as a.foo = true; that would be included in iterating with for..in but not in for.
Please don't use for..in to loop arrays. Not. Ever.
To explain why a for loop is faster than a for in loop is basically understand the underlying data structures used to store the data in memory.
Looping through an indexed based array is naturally faster because of the way an array is stored in memory. It's just a location in memory and the items in the array are stored in consecutive locations, aka. in order and next to each other. Generally it's fast to retrieve elements in consecutive order because you don't have to spend time to find it, you just know the next item is always the next location beside it. And because it knows the array.length and can determine which chunks of memory has been portioned off for the array.
It really depends on the JavaScript engine implementation. Because JavaScript is dynamically typed, the interpreter has to do some work to establish the type of a given variable. I suspect there are optimisations in the engine for the classic integer iterator for loop that aren't available when using for...in.
EDIT:
for..in iterates through the enumerable properties of a variable, so var i is assigned the value of each string in your array on each loop.
I'm making a small jQuery-like library, and one thing striking me odd is the behavior of $.each.
In javascript we have a for...in loop:
for (var key in obj) {
console.log(key + ': ' + obj[key]);
}
The problem with this, is that it will iterate over inherited properties as well, that is, properties coming from the object constructor's prototype.
One can know this using hasOwnProperty, for example. And jQuery could do that.
But, when you pass an object to $.each, it behaves exactly like a for...in, iterating over inherited properties as well. It also should be marginally slower, and requires a few more characters to type.
Check this fiddle to see it in action and look here for the source code of $.each.
So my question is, is there an object iteration method in jQuery that only includes own properties? If not, should a library behave like this?
Edit: Since jQuery does not do this, you can also answer if this is useful. I mean, I cannot see myself wanting to iterate over prototype properties, but maybe I'm missing something.
The jQuery behavior makes sense, as you can always choose to add the hasOwnProperty check in the loop - or not.
I can see that looping through inherited properties could be useful in some scenarios (cloning or sub-class or whatever you call it).
I'm trying to use the 'arguments' variable available to a function in order to enumerate the arguments passed to a function, in Javascript, using :
for (var i in arguments){
...
}
This seems to be working for me in the chrome and firebug consoles, while does not work with Rhino. With the former two, I can successfully enter the for loop and see the arguments, while with the latter, it doesn't seem like the for loop is even entered.
Why is this happening and how can I prevent this ?
From Javascript for..in looping over arguments ie.for( arg in arguments) does not work in IE8 but it works in Chrome 8 :
First of all, while the arguments object available within a function is not an array, it is "array-like" enough such that an incremental for loop (for (var i = 0, len = arguments.length; i < len; i++) { ... }) is preferable - not only because it runs faster, but also because it avoids other pitfalls - one of which is exactly what you're falling into.
To actually answer the question of why the second loop doesn't work, it's important to realize just what for ... in loop does: it iterates through all enumerable properties found in an object. Now, I've bolded 2 words in that statement, because I used these two words purposefully to indicate a couple of nuances that, while they may seem subtle, can drastically affect the behavior of your code if you don't realize what's going on.
First let's focus on all - by which I mean to say, not just properties of the object itself, but also potentially properties said object has inherited from its prototype, or its prototype's prototype, or so on. For this reason, it is very often recommended that you "guard" any for ... in loop by immediately additionally qualifying it with the condition if (obj.hasOwnProperty(p)) (assuming your loop were written for (var p in obj)).
But that's not what you're running into here. For that, let's focus on that second word, enumerable. All properties of objects in JavaScript are either enumerable or non-enumerable, which pretty much directly relates to whether the property shows up in a for ... in loop or not. In browsers such as Firefox and IE, as it turns out, the arguments object's numeric properties are not enumerable (nor is its length as it were), which is precisely why you're not iterating through anything!
A clientside javascript library I've developed uses objects as hashes in some areas. It loops through objects parsed from Json data with a for...in loop using the property name as a key. eg... (pseudo code)
var conversations = {'sha1-string':{name:'foo',messages:[]}}
for(var id in conversations){
console.log(id);
console.log(conversations[id].name);
}
Unfortunately MooTools (and Prototype, etc) add methods to the global namespaces, so my for...in loops now iterate through MooTools' additions (eg. limit, round, times, each), causing errors when it applies logic to them as if it were the data expected.
As it's a library, I have to expect that it will be used with MooTools, Prototype, etc. Is there an easy way around this problem? My current solution is just to pass the object to a method which strips out the MooTools specific entries and returns the clean object, but this means also checking what Prototype and all similar libraries out there add, and seems to be a backwards way of doing things.
My other solution is to stop relying on the property name as a key, and perform validation in the loops to ensure I'm looking at the data I want to. Before I do that rewriting though, I'm wondering if anyone has a better/existing solution?
Thanks :)
If your clientside objects are not inherited from other custom objects, you see if you could use the javascript's Object.hasOwnProperty method to find out if a certain property exists in the object itself and not up in the inheritance chain via the prototype object.
For browsers that don't support this method, you can write a wrapper around to check:
var hasOwnProperty = function(object, property) {
if(object.hasOwnProperty) {
return object.hasOwnProperty(property);
}
var prop = object[property];
return typeof(prop) !== "undefined" && prop !==
object.constructor.prototype[property];
}
How to use it:
for(var key in someObj) {
if(hasOwnProperty(someObj, key)) {
// we are good to go!
}
}
If I got it correctly, you are looking for the hasOwnProperty() method.
As "limit", "round", "times" and "each" are all additional methodes of the Array prototyp you're main failure is to use "for in" to iterate over arrays. You should check the type of the object before and use "for in" only for objects and "for" for arrays.
Btw. "for in" is the slowest method to iterate over arrays.
Using both MooTools and Prototype isn't a very good idea as they modify the base prototypes and can't co-exist peacefully. That said, none of them modify Object.prototype (not anymore) so you should not see any other properties besides your own.
Did you add a plugin which is perhaps adding these properties there? Could you give a more complete example that shows where these properties are getting listed and also the versions of these libraries that you are using?
hasOwnProperty checks will solve the prototype problem, but this shouldn't be needed in the first place, so maybe it's better to find out exactly which script is messing up.
MooTools has created a Hash type just because they didn't want to modify Object.prototype. Here's a quote from the docs:
Hash
A custom Object ({}) implementation which does not account for prototypes when setting, getting, or iterating. Useful because in JavaScript, we cannot use Object.prototype. Instead, we can use Hash.prototype!