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!
Related
What is the main difference between for loops and for..of loops in the context of iterating over an array?
Why does this code
for (let n of at.neighbours) {
DFS(n);
}
give different output than this code?
for (let i = 0; i < at.neighbours.length; i++) {
n = at.neighbours[i]
DFS(n);
}
This is my function btw:
function DFS(at) {
if (at.visited) return;
at.visited = true
// for (let i = 0; i < at.neighbours.length; i++) {
// n = at.neighbours[i]
// DFS(n);
// }
// This gives desired output
for (let n of at.neighbours) {
DFS(n);
}
}
Basic Difference
for statement allows you to iterate over iterable objects while controlling the start and the terminating condition.
for...of can also be used to iterate over iterable objects(arrays and array-like objects and user-defined iterables). The operation is executed on the value of each distinct property unless it is terminated by using break, return, or throw keywords.
forEach method is available as a prototype method of iterable objects but it is executed for each element unless an error is thrown. (Ideally should be used only if the operation is to be executed on every element)
In terms of performance,
for statement outperforms all other iteration statements. Refer to this
In terms of support,
for statement is supported widely across browsers. Link
for...of is still not supported in Internet Explorer. Link
forEach is also supported widely for arrays. Link
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'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()
Hopefully I can ask this in an understandable way...
Overall, I am trying to determine what type of object I am currently dealing with.
I'm creating a collection (HTML is example, not literal) and I need to filter my collection to certain elements eg:
<div id="tabContentWrap">
<div id="tab">
Link Element<img src="img.jpg" alt="img" />
<select id="my_select"><option value="1">1</option></select>
</div>
</div>
function getFilteredElements() {
var tabContent = getElementsByClass("tabContentWrap", document.getElementById(tabWrapId), "div");
for (var j = 0; j < tabContent.length; j++){
tabContentLinks = tabContent[j].getElementsByTagName('*');
for (var k = 0; k < tabContentLinks.length; k++){
// Here i attempt to filter the collection
if (tabContentLinks[k] == '[object HTMLSelectElement]') {
alert("found select list");
}
}
}
}
Which works fine in Mozilla but not in Internet Explorer 8, tabContentLinks[k] returns [object] instead of [object 'ObjectType']
So I investigated and discovered that you can use Object.prototype.toString.call(object) to get the object type, which again works fine in Mozilla but returns [object Object] in IE8...
I call
get_type(tabContentsLink[k]);
which runs the following function:
function get_type(thing){
if (thing === null) return "[object Null]";
// special case
return Object.prototype.toString.call(thing);
}
But this just returns [object Object]
Does Object.prototype.toString.call() ever return the type of object in IE or am I very far off and barking up a lamppost instead of a tree?
Well, first of all I want to tell you that Object.prototype.toString returns the value of the object's internal [[Class]] property, it isn't really a Type.
The value of this internal property represents the specification defined classification of an object (more info here).
Javascript has only 6 language types: Object, String, Number, Boolean, Null and Undefined, that's it.
The value of the [[Class]] internal property for host objects -as DOM elements- can be anything, it is completely implementation-dependent, on built-in objects is safe to use it -except with some exceptions in IE as #Alex pointed out in the article linked in his answer-.
You are working with DOM elements, and you want to figure out what kind of node it is, my suggestion to this, is to simply use the nodeName property (please avoid using tagName).
The nodeName property contains the name of the node you are dealing it, in upper case, therefore you could use it as this:
function getFilteredElements() {
var tabContent = getElementsByClass("tabContentWrap",
document.getElementById(tabWrapId), "div");
for (var j = 0; j < tabContent.length; j++){
tabContentLinks = tabContent[j].getElementsByTagName('*');
for (var k = 0; k < tabContentLinks.length; k++){
// Here i attempt to filter the collection
if (tabContentLinks[k].nodeName == 'SELECT') { // <- SELECT elements
alert("found select list");
}
}
}
}
Rather than recreate the entire discussion and possible solutions, I'll just point you to a blog post that discusses this exact issue.
I believe IE will return simple data types, but everything else is just an object. It's a browser limitation. I don't know if IE9 is improving the situation, but that probably wouldn't help you anyway.
I don't have IE handy, but the proper way in Firefox is to use object.constructor.name (object.constructor being the object's constructor, .name being the function name).
function Xyz() {}
new Xyz().constructor.name === 'Xyz'
But then, also,
var Abc = function() {}
new Abc().constructor.name === 'Abc'