I'm currently working with some data using Javascript that is in the form of an array. The array may contain an empty entry at the end, such as [1,2,]. In Google Chrome and Firefox, the length of that example would be 2; however, in IE, the length is 3.
In short: Internet Explorer is giving a different length for an array in Javascript than Google Chrome and Firefox. Is there a way to standardize this behavior across all browsers?
Code:
var a = [1,];
alert(a.length);
EDIT:
A lot of answers are saying not to have a trailing comma, however, the data is given to me in this way.
NEVER have trailing commas in IE. Period.
That goes for ARRAYs too
Javascript Browser Quirks - array.Length
To handle your edit this works (tested in in IE8):
if (a[a.length-1]==null) a.length--; // or a.pop()
For a safer test, please look at the other suggestion on this page: Length of Array Differs In Internet Explorer With Trailing Comma - DEMO HERE
By the way, never heard the words elision or elided before - learn something new here every day
No. IE incorrectly interprets a single trailing comma as an elision and adds one to the length when it shouldn't (ECMA-262 sect. 11.1.4).
Edit
To clear up the confusion here, IE treats a single trailing comma in an array literal (incorrectly) as an elision, which means it increments array's length property but does not create a property. In other words, given:
var a = [0,1,];
In IE, a.length is 3, but there is no property a[2]. So if an appropriate solution is to remove only elided members from the end of an array (which is likely the best solution if they are an issue), then:
function tidyTrailingElisions(array) {
var i = array.length;
while (!array.hasOwnProperty(--i)) {}
array.length = ++i;
return array;
}
will remove only elided members from the end of the array (that is, properties that don't exist), it will not remove them elsewhere, nor will it waste time iterating over the entire array (which can result in elided members being added as undefined). To add to Array.prototype:
Array.prototype.tidyTrailingElisions = function() {
var i = this.length;
while ( !this.hasOwnProperty(--i)) {}
this.length = ++i;
return this;
};
Note that this is how Array.prorotype.filter works, it doesn't iterate over elided members (it uses a hasOwnProperty test and removes any elided mebers as part of filtering the array).
Try removing empty elements:
a = a.filter(function(){return true});
Then it should work the same way in IE and other browsers.
Update: if the JS version is lower than 1.6, try this:
Array.prototype.clean = function() {
for (var i = 0; i < this.length; i++) {
if (this[i] == undefined) {
this.splice(i, 1);
i--;
}
}
return this;
};
a.clean()
Related
I found myself needing to convert from a small integer into a corresponding, arbitrary string. The obvious way to do this is with an Array. But I also wanted to go back the other way: given the string, find the corresponding integer. Obviously I could do this by Array.indexOf(), but handling the 'no match found' case was a bit awkward. But in Javascript, Arrays are Objects, and Objects have properties, so I tried defining a function:
var reflect = function(array) {
for (var i = 0; i < array.length; i++) {
array[array[i]] = i;
}
};
which adds a property corresponding to each array element. So given:
lighting2 = ['AC', 'HOMEEASY_EU', 'ANSLUT'];
reflect(lighting2);
I can write lighting2[1] giving me 'HOMEEASY_EU'; and also lighting2['HOMEEASY_EU'] which gives me 1. Furthermore, lighting2['FOO'] gives me undefined as it ought to. The Array.length property does not appear to be affected by this 'reflection'. The technique works - at least it works in node.js - but I have never seen it before. Is this 'legal'? Will it cause nasty things to happen? Is it likely to be useable in all Javascript implementations?
Cue the Javascript language lawyers!
First off I want to say I know there are easy ways around this issue but just by googleing and looking on stackoverflow it doesn't seem like there is a set way you are suppose to go about doing this so I wanted to see if anyone out there had ran into this before and came out with a nice solution. Here is my issue, I want to add an additional property for each property in an object. This works fine in newer IEs and in Firefox but will cause an infinite loop in IE8.
var oObject = { One : '1', Two : '2' };
for ( var key in oObject ) // Loops twice in IE10 and FF, loops infinitely in IE8
{
console.log(oObject[key]);
oObject[key+'_additionalProperty'] = 'Test';
}
Is there a way to do this without having to create a variable that holds the original value of oObject just to add an additional property for each property in oObject?
Note: For those jQuery fans out there $.each has the same issue. Also, I wish I could just not support IE8.
UPDATE:
JSFIDDLE: http://jsfiddle.net/dwaddell/rH89K/
Additional information: I actually haven't tested this in a true IE browser, I have been using the Developer Tools from IE10 and selecting IE8 for Browser Mode and IE 8 standards for Document Mode. This may make some kind of difference, I am not sure.
Apparently, IE8 doesn't cache the properties list when using for...in. So, you continually add keys... adding additional properties for your additional properties and so on.
At any rate, a safeguard is to get your keys first like so (fiddle):
var oObject = {
One: '1',
Two: '2'
};
var keys = []; // plain array for caching our keys
// add keys to our cache
for (var key in oObject) {
keys.push(key);
}
// loop through the cached keys and add new properties to oObject
for (var i = 0, ln = keys.length; i < ln; i++) {
oObject[keys[i] + "_additionalProperty"] = "test";
}
console.log(oObject);
var oObject = { One : '1', Two : '2' };
var keys = Object.keys(oObject);
for ( var i=0;i<keys.length;i++) // Loops twice in IE10 and FF, loops infinitely in IE8
{
oObeject[keys[i]+'_additionalProperty'] = 'Test';
}
Edit:
Your code should work as it is:
http://msdn.microsoft.com/en-us/library/ie/gg622937(v=vs.85).aspx
Edit 2:
An implementation of Object.Keys for ie8
Object.keys = Object.keys || function(o) {
var result = [];
for(var name in o) {
if (o.hasOwnProperty(name))
result.push(name);
}
return result;
};
http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
Using the jQuery for-loop is quite slow, which is the reason why I'm considering using the regular for-statement more often. In order to have direct access to the current element, I found the following syntax (for regular arrays, not for objects of course):
for (var i = 0, e; e = array[i]; i++) { ... }
where e in the loop represents the current element.
Is this syntax safe to use across all browsers?
Addition
OK, I guess this could work, but it is not so useful anymore for a short notation:
for (var i = 0, e; (e = array[i]) !== void(0); i++) { ... }
Thank you all for answering!
That is not a very good loop. Consider this array:
var array = [0, 1, 2, 3];
It would stop on the first element because 0 is a falsey value. Same with
var array = ["foo", "bar", false, "hello"];
It would only get to "foo" and "bar"
Consider using this loop
for (var i=0, len=array.length; i<len; i++) { ... }
It works everywhere, only calculates array.length once, and is plenty performant.
Per T.J.'s comment, the scope of the args i and len above will exist your current function. So be careful that you don't make variable conflicts.
A somewhat common (but clunky) way of safeguarding against this is prefixing vars with _. Like this
for (var _i=0, _len=array.length; _i<_len; _i++) { ... }
I do not recommend that. You see, if your array looks like this for example:
array = ["lala", 078, false, 992, "kas"];
Then your loop would only go through the first two, since the term e = array[i]; would return false, because the third entry in the array is literally false.
This is better:
for (var i = 0, e; (e = array[i])===undefined; i++) { ... }
Make sure no one overwrites the undefined variable, e.g. by using a closure: How does this JavaScript/JQuery Syntax work: (function( window, undefined ) { })(window)?
As naomik points out, that form of loop will break if any of the array elements has a falsey value. Falsey values are false, null, undefined, "", 0, and NaN. So it would work, for instance, for an array of non-null object references. Not so much for an array of strings or numbers.
But if your question is about the syntax, then yes, it's "safe" in that it will work (and fail on falsey elements) in all JavaScript engines. The key bits you're relying on are:
That accessing the element beyond the end of the array (e.g., at array[array.length]) will give you a falsey value (undefined) rather than throwing an exception, and
That the result of an assignment expression (e = array[i]) is the value that was assigned.
Yes, both of those are reliable. (Well, #1 is reliable if the array really is a JavaScript array. Host-provided array-like objects may vary.)
In any case, note that neither i nor e is scoped only to the loop. ES6 will have let, which will be, but variables declared with var are scoped to the function they're in.
I want to know why the results of running the following code in the different browsers have differents?
(function () {
//will alert 1, 2, 3 in IE 9, Firefox 8+, Chrome 15,
// Opera 11 but not in IE 7, 8 and Safari 5
for (var a in arguments)
alert(arguments[a]);
})(1,2,3);
Because the browsers have different implementations of the arguments object. For a cross browser method use the length property instead.
(function () {
for (var i=0, nLength = arguments.length; i < nLength; i++) {
alert(arguments[i]);
}
})(1,2,3);
The arguments object is actually not an array, though it behaves like one in some ways. It's a special object that lacks most of a JavaScript array's methods by default (though you could apply these methods manually using apply()), and includes a length property.
In order to access the arguments themselves, just iterate over the arguments object with a standard for loop. JavaScript's for-in statement works over the contents of arrays, with some critical exceptions, but not this array-like structure.
for (var i = 0, numArgs = arguments.length; i < numArgs; i++) {
console.log( arguments[i] );
}
Hope that helps!
I am currently creating a website and have some javascript that works in all browsers except IE7 and IE8. I have done some tests on the code by inserting several 'alert' statements and deduced that the javascript breaks at one particular 'if' statement. It is not the code within the 'if' statement either because I have also tested this.
I can't see anything wrong with the actual 'if' statement myself but please let me know if there is a problem with IE7/IE8 and the code I have produced. The code can be seen below.
Thanks in advance for any help.
var Items = new Array("a","b","c","d");
var queryString = window.location.search.substring(1);
if(Items.indexOf(queryString) != "-1"){
//code goes here
}
There's no "indexOf()" function on IE's Array prototype. If there were, it'd return a numeric value and not a string.
You can find an "indexOf()" polyfill at the MDN documentation page for the function.
Also, when you declare and initialize arrays, use array constant notation:
var Items = ["a", "b", "c", "d"];
Here is one way of extending the Array object to support indexOf in those browsers that don't support it. Doing this has its own issues, if you ever iterate an array via for (x in a) (not suggested) and don't check hasOwnProperty this will cause you problems.
if(!Array.indexOf){
Array.prototype.indexOf = function(obj){
for(var i=0; i<this.length; i++){
if(this[i]==obj){
return i;
}
}
}
}