JS中的for循环

for语法主要有如下四种用法:

1. for-of,是比较新for语法,但是兼容性有问题
for (var object of arrays) {}
(ES2015+ only)

2. Array#forEach,同样存在兼容性问题
Array.prototype.forEach.call(node.childNodes, function(child) {}
(ES5+ only)

3. for-in,其实是和for-i一样的用法,初学者会误以为是for-of
for (var key in arrays) {
var object = arrays[key];
}

4. for-i, 这个是最常用的用法,也是最推荐的用法
for (var i=0; i<arrays.length; i++) {
var object = arrays[i];
}

======================================================================

 

JavaScript has powerful semantics for looping through arrays and array-like objects. I’ve split the answer into two parts: Options for genuine arrays, and options for things that are just array-like, such as the arguments object, other iterable objects (ES2015+), DOM collections, and so on.

I’ll quickly note that you can use the ES2015 options now, even on ES5 engines, by transpilingES2015 to ES5. Search for “ES2015 transpiling” / “ES6 transpiling” for more…

Okay, let’s look at our options:

For Actual Arrays

You have three options in ECMAScript 5 (“ES5”), the version most broadly supported at the moment, and will soon have two more in ECMAScript 2015 (“ES2015”, “ES6”), the latest version of JavaScript that vendors are working on supporting:

  1. Use forEach and related (ES5+)
  2. Use a simple for loop
  3. Use for-in correctly
  4. Use for-of (use an iterator implicitly) (ES2015+)
  5. Use an iterator explicitly (ES2015+)

Details:

1. Use forEach and related

If you’re using an environment that supports the Array features of ES5 (directly or using a shim), you can use the new forEach (spec | MDN):

var a = ["a", "b", "c"];
a.forEach(function(entry) {
    console.log(entry);
});

forEach accepts an iterator function and, optionally, a value to use as this when calling that iterator function (not used above). The iterator function is called for each entry in the array, in order, skipping non-existent entries in sparse arrays. Although I only used one argument above, the iterator function is called with three: The value of each entry, the index of that entry, and a reference to the array you’re iterating over (in case your function doesn’t already have it handy).

Using forEach on a general-purpose web page still (as of March 2014) requires that you include a “shim” for it for browsers that don’t support it natively, because IE8 and earlier don’t have it (and they’re used by somewhere between 7% and 21% of the global browser users depending on who you believe; that figure is skewed a bit by markedly higher use in China vs. elsewhere, always check your own stats to see what you need to support). But shimming/polyfilling it is easily done (search for “es5 shim” for several options).

forEach has the benefit that you don’t have to declare indexing and value variables in the containing scope, as they’re supplied as arguments to the iteration function, and so nicely scoped to just that iteration.

If you’re worried about the runtime cost of making a function call for each array entry, don’t be; details.

Additionally, forEach is the “loop through them all” function, but ES5 defined several other useful “work your way through the array and do things” functions, including:

  • every (stops looping the first time the iterator returns false or something falsey)
  • some (stops looping the first time the iterator returns true or something truthy)
  • filter (creates a new array including elements where the filter function returns true and omitting the ones where it returns false)
  • map (creates a new array from the values returned by the iterator function)
  • reduce (builds up a value by repeated calling the iterator, passing in previous values; see the spec for the details; useful for summing the contents of an array and many other things)
  • reduceRight (like reduce, but works in descending rather than ascending order)

2. Use a simple for loop

Sometimes the old ways are the best:

var index;
var a = ["a", "b", "c"];
for (index = 0; index < a.length; ++index) {
    console.log(a[index]);
}

If the length of the array won’t change during the loop, and it’s in performance-sensitive code (unlikely), a slightly more complicated version grabbing the length up front might be a tiny bit faster:

var index, len;
var a = ["a", "b", "c"];
for (index = 0, len = a.length; index < len; ++index) {
    console.log(a[index]);
}

And/or counting backward:

var index;
var a = ["a", "b", "c"];
for (index = a.length - 1; index >= 0; --index) {
    console.log(a[index]);
}

But with modern JavaScript engines, it’s rare you need to eke out that last bit of juice.

3. Use for-in correctly

You’ll get people telling you to use for-in, but that’s not what for-in is forfor-in loops through the enumerable properties of an object, not the indexes of an array. Up through ES5, the order is not guaranteed; as of ES2015, the order is guaranteed (by [[OwnPropertyKeys]][[Enumerate]], and the definition of for-in/for-of). (Details in this other answer.)

Still, it can be useful, particularly for sparse arrays, if you use appropriate safeguards:

// `a` is a sparse array
var key;
var a = [];
a[0] = "a";
a[10] = "b";
a[10000] = "c";
for (key in a) {
    if (a.hasOwnProperty(key)  &&        // These are explained
        /^0$|^[1-9]\d*$/.test(key) &&    // and then hidden
        key <= 4294967294                // away below
        ) {
        console.log(a[key]);
    }
}

Note the two checks:

  1. That the object has its own property by that name (not one it inherits from its prototype), and
  2. That the key is a base-10 numeric string in its normal string form and its value is <= 2^32 – 2 (which is 4,294,967,294). Where does that number come from? It’s part of the definition of an array index in the specification. Other numbers (non-integers, negative numbers, numbers greater than 2^32 – 2) are not array indexes. The reason it’s 2^32 – 2 is that that makes the greatest index value one lower than 2^32 – 1, which is the maximum value an array’s lengthcan have. (E.g., an array’s length fits in a 32-bit unsigned integer.) (Props to RobG for pointing out in a comment on my blog post that my previous test wasn’t quite right.)

That’s a tiny bit of added overhead per loop iteration on most arrays, but if you have a sparse array, it can be a more efficient way to loop because it only loops for entries that actually exist. E.g., for the array above, we loop a total of three times (for keys "0""10", and "10000" — remember, they’re strings), not 10,001 times.

Now, you won’t want to write that every time, so you might put this in your toolkit:

function arrayHasOwnIndex(array, prop) {
    return array.hasOwnProperty(prop) && /^0$|^[1-9]\d*$/.test(prop) && prop <= 4294967294; // 2^32 - 2
}

And then we’d use it like this:

for (key in a) {
    if (arrayHasOwnIndex(a, key)) {
        console.log(a[key]);
    }
}

Or if you’re interested in just a “good enough for most cases” test, you could use this, but while it’s close, it’s not quite correct:

for (key in a) {
    // "Good enough" for most cases
    if (String(parseInt(key, 10)) === key && a.hasOwnProperty(key)) {
        console.log(a[key]);
    }
}

4. Use for-of (use an iterator implicitly) (ES2015+)

ES2015 adds iterators to JavaScript. The easiest way to use iterators is the new for-ofstatement. It looks like this:

var val;
var a = ["a", "b", "c"];
for (val of a) {
    console.log(val);
}

Output:

a
b
c

Under the covers, that gets an iterator from the array and loops through it, getting the values from it. This doesn’t have the issue that using for-in has, because it uses an iterator defined by the object (the array), and arrays define that their iterators iterate through their entries (not their properties). Unlike for-in in ES5, the order in which the entries are visited is the numeric order of their indexes.

5. Use an iterator explicitly (ES2015+)

Sometimes, you might want to use an iterator explicitly. You can do that, too, although it’s a lot clunkier than for-of. It looks like this:

var a = ["a", "b", "c"];
var it = a.values();
var entry;
while (!(entry = it.next()).done) {
    console.log(entry.value);
}

The iterator is a function (specifically, a generator) that returns a new object each time you call next. The object returned by the iterator has a property, done, telling us whether it’s done, and a property value with the value for that iteration.

The meaning of value varies depending on the iterator; arrays support (at least) three functions that return iterators:

  • values(): This is the one I used above. It returns an iterator where each value is the value for that iteration.
  • keys(): Returns an iterator where each value is the key for that iteration (so for our aabove, that would be "0", then "1", then "2").
  • entries(): Returns an iterator where each value is an array in the form [key, value] for that iteration.

(As of this writing, Firefox 29 supports entries and keys but not values.)

For Array-Like Objects

Aside from true arrays, there are also array-like objects that have a length property and properties with numeric names: NodeList instances, the arguments object, etc. How do we loop through their contents?

Use any of the options above for arrays

At least some, and possibly most or even all, of the array approaches above frequently apply equally well to array-like objects:

  1. Use forEach and related (ES5+)

    The various functions on Array.prototype are “intentionally generic” and can usually be used on array-like objects via Function#call or Function#apply. (See the Caveat for host-provided objects at the end of this answer, but it’s a rare issue.)

    Suppose you wanted to use forEach on a Node‘s childNodes property. You’d do this:

    Array.prototype.forEach.call(node.childNodes, function(child) {
        // Do something with `child`
    });

    If you’re going to do that a lot, you might want to grab a copy of the function reference into a variable for reuse, e.g.:

    // (This is all presumably in some scoping function)
    var forEach = Array.prototype.forEach;
    
    // Then later...
    forEach.call(node.childNodes, function(child) {
        // Do something with `child`
    });
  2. Use a simple for loop

    Obviously, a simple for loop applies to array-like objects.

  3. Use for-in correctly

    for-in with the same safeguards as with an array should work with array-like objects as well; the caveat for host-provided objects on #1 above may apply.

  4. Use for-of (use an iterator implicitly) (ES2015+)

    for-of will use the iterator provided by the object (if any); we’ll have to see how this plays with the various array-like objects, particularly host-provided ones.

  5. Use an iterator explicitly (ES2015+)

    See #4, we’ll have to see how iterators play out.

Create a true array

Other times, you may want to convert an array-like object into a true array. Doing that is surprisingly easy:

  1. Use the slice method of arrays

    We can use the slice method of arrays, which like the other methods mentioned above is “intentionally generic” and so can be used with array-like objects, like this:

    var trueArray = Array.prototype.slice.call(arrayLikeObject);

    So for instance, if we want to convert a NodeList into a true array, we could do this:

    var divs = Array.prototype.slice.call(document.querySelectorAll("div"));

    See the Caveat for host-provided objects below. In particular, note that this will fail in IE8 and earlier, which don’t let you use host-provided objects as this like that.

  2. Use the spread operator (...)

    It’s also possible to use the ES2015 spread operator, with JavaScript engines that support this feature:

    var trueArray = [...iterableObject];

    So for instance, if we want to convert a NodeList into a true array, with spread syntax this becomes quite succinct:

    var divs = [...document.querySelectorAll("div")];

Caveat for host-provided objects

If you use Array.prototype functions with host-provided array-like objects (DOM lists and other things provided by the browser rather than the JavaScript engine), you need to be sure to test in your target environments to make sure the host-provided object behaves properly. Most do behave properly (now), but it’s important to test. The reason is that most of the Array.prototypemethods you’re likely to want to use rely on the host-provided object giving an honest answer to the abstract [[HasProperty]] operation. As of this writing, browsers do a very good job of this, but the ES5 spec did allow for the possibility a host-provided object may not be honest; it’s in §8.6.2(several paragraphs below the big table near the beginning of that section), where it says:

Host objects may implement these internal methods in any manner unless specified otherwise; for example, one possibility is that [[Get]] and [[Put]] for a particular host object indeed fetch and store property values but [[HasProperty]] always generates false.

(I couldn’t find the equivalent verbiage in the ES2015 spec, but it’s bound to still be the case.) Again, as of this writing the common host-provided array-like objects in modern browsers (NodeList instances, for instance) do handle [[HasProperty]] correctly, but it’s important to test.

jquery.fadeout()在IE8下png图片透明问题

问题描述:AD杂志iPad版需要一个查看礼物的网站,有个效果是png带透明图片用jquery进行fade in和fade out。原本只需要在iPad上使用。结果客户说IE8运行的时候透明的不会呈现全黑。检查后发现Safari、Firefox、Chromx都正常浏览,唯独IE7、8会有问题。

问题分析:猜想是IE7、8对png的兼容问题。原因是:IE修改透明度,不是通过css属性,而是通过filter滤镜。在IE9,微软修复了此问题。但是此问题对于IE7、8是无解。

总结:IE实在是弱爆了。

javascript中获取地址栏参数

index.asp?id=xxx&name=xxx

方法一:

 <script>
function getvalue(name)
{
 var str=window.location.search;
 if (str.indexOf(name)!=-1)
 {
  var pos_start=str.indexOf(name)+name.length+1;
  var pos_end=str.indexOf(“&”,pos_start);
  if (pos_end==-1)
  {
   return str.substring(pos_start);
  }
  else
  {
   return str.substring(pos_start,pos_end)
  }
 }
 else
 {
  return “没有这个name值”;
 }
}
var strName=prompt(“请输入您所要值的名字”);
alert(getvalue(strName));
</script>

方法二:

var URLParams = new Array();
var aParams = document.location.search.substr(1).split(‘&’);
for (i=0; i < aParams.length  i++){
 var aParam = aParams.split(‘=’);
 URLParams[aParam[0]] = aParam[1];
}

//取得传过来的name参数
name=URLParams[“name”];

方法三:

<script type=”text/javascript”>
Request = {
 QueryString : function(item){
  var svalue = location.search.match(new RegExp(“[\?\&]” + item + “=([^\&]*)(\&?)”,”i”));
  return svalue ? svalue[1] : svalue;
 }
}
alert(Request.QueryString(“id”));
</script>

javascript用Enter键实现Tab键功能

<script language=”javascript” for=”document” event=”onkeydown”>

<!–

  if(event.keyCode==13 && event.srcElement.type!=’button’ && event.srcElement.type!=’submit’ && event.srcElement.type!=’reset’ && event.srcElement.type!=’textarea’ && event.srcElement.type!=”)

     event.keyCode=9;

–>

</script>

判断是否为button, 是因为在HTML上会有type=”button”

判断是否为submit,是因为HTML上会有type=”submit”

判断是否为reset,是因为HTML上的”重置”应该要被执行

判断是否为空,是因为对于HTML上的”<a>链接”也应该被执行,这种情况发生的情况不多,可以使用”tabindex=-1″的方式来取消链接获得焦点.

PS:以下是VS没有警告的代码:
<script type=”text/javascript”>
       document.onkeydown = function(){if(event.keyCode==13 && event.srcElement.type!=’button’ && event.srcElement.type!=’submit’ && event.srcElement.type!=’reset’ && event.srcElement.type!=’textarea’ && event.srcElement.type!=”)
       event.keyCode=9; }
</script>