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.

《捉妖记》

其实导演想讲的是如下,可惜表面的戏比较重。

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

  一
  《捉妖记》做到了一件了不起的事。
  如果你把它当作消磨时间的爆米花电影,它很好看,剧情扎实、逻辑严密、质感精致、制作精良、动作场面有力、笑点泪点都高级有趣,主角配角的表演都很精彩,过来客串的一众演员也都鲜明好玩,一路又哭又笑地看完,会觉得特别对得起票价。
  如果你想要从一部电影里得到更多,比如厚重的深刻、比如诚恳的情怀、比如关于人与所处世界关系的思考,《捉妖记》也一样可以带给你。
  让娱乐者得到娱乐,让思考者得到思考。
  这很了不起。
  二
  电影里有两个大泪点,一是霍小岚和宋天荫卖掉胡巴,二是结尾两人为了胡巴的安全而送他离开。
  但其实还有一个更隐秘的泪点。
  在结尾,宋天荫与胡巴告别的时候,他跟胡巴说:“走吧,找个没人的地方好好生活,现在这个世界还没办法接受你,我把你留在身边,会害了你。”
  我听到这句话,一下子就不行了。
  就在看《捉妖记》之前,蔡康永在《奇葩说》因为谈到“出柜”话题而失声痛哭的视频在微博传得很热闹,他说当人们向他咨询要不要出柜的时候,他通常会拦一下,因为他不确定当他们要经历他经历过的事情时,他们能不能像他一样扛得住,如果他们扛不住,他有可能没办法伸手过去保护他们。
  社交网络的火热氛围常常让我们误以为这个世界已经足够宽容。
  很多名人都参与了反歧视的线上活动啊。
  有大堆大堆的年轻人在努力转发着不公正不光明的新闻,表达着自己的愤慨啊。
  甚至越来越多的主流媒体也将目光投向了曾经被忽视过的社会角落。
  可针对内向敏感孤僻脆弱的小孩的校园暴力依然存在,出了柜的明星再难接到直人角色依然是事实,那些只是因为没有占据社会主流多数派而遭受打压、无法抬头生活的人仍旧到处都能见到。
  我们曾经以为当年轻人开始长大、开始掌握话语权,我们就能拥有一个更好的世界。
  可越来越多的事实证明,那是错觉。
  依然有那么多人无法勇敢做自己,依然有那么多人没办法牵着爱人的手走在阳光下,依然有那么多人不得不披上一层伪装,加倍辛苦地生活。
  就像《捉妖记》里那个永宁村,妖们披上人皮,装作人类,褪去妖气,不再吃肉,他们努力地让自己融入人类社会,即便那需要舍弃部分的自我。
  可人类社会并没有因此而对他们有所宽容,反而将他们逼向了更遥远、更荒芜、更杳无人烟的深山老林。
  三
  当葛千户带着天师们来到永宁村,与一村子妖对峙,那个在电影一开头就格外彪悍的大娘指着他的鼻子说,我们全都改吃素,我们安生地在这里生活了这么多年,已经证明了人和妖能够和平共存,你们人类已经把那么多动物都搞灭绝了,为什么还没有接受教训,为什么就是不能放我们一条生路。
  就因为这个世界上人类是大多数的存在,而妖是少数派的存在。
  人多势众本身就是正义,你还有什么意见吗?
  作为少数派就应该有少数派的觉悟,乖乖束手就擒不就好了吗?
  你们不过就是盘中餐,你见过人类与一块牛排讲人道主义吗?
  可这从来不是、也不应该是人类在进步中所拥有的价值判断。
  在经历一路艰险,终于到达顺天府,霍小岚执意要把胡巴卖了换钱时,她和宋天荫有过一段很精彩的争论。
  霍小岚说:“就算你舍不得他!但他是妖!他有感情吗!”
  宋天荫含着眼泪喊:“就算他没有感情!我有!”
  这才是人之所以能为人的原因。
  当如今的我们越来越相信优胜劣汰,越来越相信对弱者的不同情才是人间正道,而越来越少人还记得:成王败寇,并不是一个值得推崇的价值观。
  当你面对一个你有能力轻易就把他们赶尽杀绝的群体时,真的选择去赶尽杀绝,这并不光彩。
  胜负之外,还有宽容,还有情怀,还有高贵。
  只是在我们的年代,所谓宽容,已然少见,所谓情怀,早被用滥。
  而高贵,现在真的还会有人诚恳地、不带戏谑地想起这个词吗。
  所以其实啊,《捉妖记》是用着一个欢乐奇幻喜剧的方式,讲了一个格外无奈残酷的故事,故事里有几个对这世界还抱有着诚恳的信念的人类,他们势单力薄,但他们用自己的血肉之躯去维护去重建那个他们坚信着的更好的世界。
  宋天荫是这样的人,霍小岚是这样的人,罗钢、奶奶,都是这样的人。
  他们依然相信,胜负、排他、强弱、优劣之外,还有正义、宽容、羁绊和共生。
  还有一个很有意思的事情是,这些依然相信着这一切的人,都是和妖一样,曾经孤立无援地站立在这世界上。
  宋天荫从小没有父母,只有一个神志不清常把他认作他人的奶奶。
  霍小岚父亲早亡,母亲不知所踪。
  奶奶则丈夫、儿子都是天师,都已早早牺牲。
  或许便是因为他们懂得孤立无援的艰难,才能在最后为了被压迫、被杀害的妖们,义无反顾。
  为孤立无援而战,为世间孤独而战,为被侮辱的与被损害的而战。
  四
  但导演许诚毅终究温柔善良,他让最后的大反派葛千户是一个冒充人类的、野心勃勃的妖,让葛千户承担了所有的矛盾冲突。
  最后的大战是发生在人+妖和反派妖之间,而没有把终极冲突指向人与妖之间。
  这很聪明,也很仁慈。
  就像我最开始说的,抱着娱乐自己的心情去看《捉妖记》,你不会失望,抱着想要从一部电影里得到更多思考的心情去看《捉妖记》,你同样不会失望。
  所以我私心希望《捉妖记》能有好的票房成绩,因为至少这样电影的存在,可以告诉大家,拍商业电影不用撕心裂肺,不用投机取巧,也一样可以拍得精彩、好看。
  以上。

Gulp版本引起的MEAN生成Error

问题描述:用命令(yo meanjs)生成mean.js的Application时,返回如下错误:

Unhandled rejection Error: Command failed: /bin/sh -c cd mean && npm install
npm WARN package.json ams@0.0.0 No repository field.
npm ERR! Darwin 14.5.0
npm ERR! argv "node" "/usr/local/bin/npm" "install"
npm ERR! node v0.12.7
npm ERR! npm v2.11.3
npm ERR! path /Users/couldhll/.npm/karma-chrome-launcher/0.2.0
npm ERR! code EACCES
npm ERR! errno -13

npm ERR! Error: EACCES, mkdir '/Users/couldhll/.npm/karma-chrome-launcher/0.2.0'
npm ERR! at Error (native)
npm ERR! { [Error: EACCES, mkdir '/Users/couldhll/.npm/karma-chrome-launcher/0.2.0']
npm ERR! errno: -13,
npm ERR! code: 'EACCES',
npm ERR! path: '/Users/couldhll/.npm/karma-chrome-launcher/0.2.0',
npm ERR! parent: 'ams' }
npm ERR!
npm ERR! Please try running this command again as root/Administrator.

npm ERR! Please include the following file with any support request:
npm ERR! /Users/couldhll/Desktop/AMS/mean/npm-debug.log

at ChildProcess.exithandler (child_process.js:751:12)
at ChildProcess.emit (events.js:110:17)
at maybeClose (child_process.js:1015:16)
at Socket.<anonymous> (child_process.js:1183:11)
at Socket.emit (events.js:107:17)
at Pipe.close (net.js:485:12)

问题解决

1.删除~/node_modules文件夹

2.清空nom的缓存:npm cache clean