开发者

Why for-in iterates through array methods also?

on a page I use similar syntax to google analitycs code, to pass parameters to another script. I iterate through the array and try to construct query part of URL according to the parameters in the included script.

The problem is the following iterates through the javascript array objects methods also and mess up resulting queryString.

开发者_运维技巧

index.html:

<script>
    var params = [];
    params['first'] = '1';
    params['second'] = '2';

    (function() {
          var vs = document.createElement('script');
          vs.async = true; vs.type = 'text/javascript';
          vs.src = 'http://my.domain.com/js/includedScript.js';
          var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(vs, s);
    })();
</script>

includedScript.js:

function(paramsArray) {
   tmpArray = [];
   for(i in paramsArray) {
      tmpArray.push(i + '=' + escape(paramsArray[i]));
   }
   var queryString = tmpArray.join('&');
}(params);

I got (shortened):

queryString == 'first=1&second=2&push&$family=function%20%28%29%20%7B%0A%20%20%20%20return%20lower%3B%0A%7D&$constructor=function%20Array%28%29%20%7B%0A%20%20%20%20%5Bnative%20code%5D%0A%7D&pop=function%20pop%28%29%20%7B%0A%20%20%20%20%5Bnative%20code%5D%0A%7D&push=function%20push%28%29%20%7B%0A%'

I expect:

queryString == 'first=1&second=2'

It's strange, that on my localhost blank page it's working well. Could some other javascript on the index.html page collide with my code? How can I fix the collision by changing only my code (preferably only the includedScript.js file)?

Thanks in advance.


One small change:

var params = {}; // notice the difference here!
params['first'] = '1';
params['second'] = '2';

and another one here

for(i in paramsArray) {
  if(paramsArray.hasOwnProperty(i)){
    tmpArray.push(i + '=' + escape(paramsArray[i]));
  }
}

JavaScript's Array should only be used with numeric indexes. For associative arrays use Object instead. Also to make sure that the properties you get were added by you and do not belong to the a prototype use hasOwnProperty.

See the documentation on mozilla.org for more info.

An array is an ordered set of values associated with a single variable name. Note that you shouldn't use it as an associative array, use Object instead.

Also you could read this article: http://andrewdupont.net/2006/05/18/javascript-associative-arrays-considered-harmful/


Note: The for ... in JavaScript construct has no connection with Array. Its purpose is to iterate over Object properties, not Array elements. In JavaScript properties also include methods.


Fun with JavaScript.

Try the following code and tell me if you're surprised:

var x = [];
x['one'] = 1;
x['one'] = 2;
alert(x.length);

then try this one:

Object.prototype.myProp = 123;
var x = {one: 1, two: 2}
for(var prop in x){
  alert(x[prop]);
}


You want to do this

for (i in paramsArray) {
    if (paramsArray.hasOwnProperty(i)) {
        ....
    }
}


You should not use for..in to iterate through array elements. Things can be prototyped onto an object automatically to make use of DOM methods or programatically by other javascript on a page (like prototyping).

You should instead get a count of array elements using .length and a normal for loop.

var l = paramsArray.length;
for (var c = 0; c < l; c++) {
  // do stuff
} 


duncan's answer is correct, and that is because the for-in loop treats the paramsArray as an object, not an array.

And as Alin mentioned, use for (var i = 0; i < paramsArray.length; i++) for arrays.


This is usually an issue when looping using for...in, which is never really recommended.

A way around it is to use the .hasOwnProperty() method to ensure you are getting your own variables:

for (var k in foo) {
    if (foo.hasOwnProperty(k)) {
       // do something with foo[k]
    }
}

Or as others have suggested, use a regular for loop:

for(var k = foo.lenght-1; k >= 0; --k) {
    // do something with foo[k]
}

Which is more efficient (especially when reversed)


I love Array.forEach(). It takes a function as an argument. That function receives the element, index, and original list as arguments.

["a","b","c"].forEach(function(item, index, list)
{
     console.log("the item at index " + index + " is " + item);
});

To make it compatible with older versions of IE, see here.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜