初學JavaScript
的時候,知道有各類for
的時候,懵懵懂懂,也許是由於沒有系統學習的緣故。如今咱們把各類for
都挨個辨明。express
for
建立一個循環,包含三個可選表達式。三個可選表達式在圓括號中,由分號分隔。後跟一個循環中執行的語句或塊語句。
for ([initialization]; [condition]; [final-expression]) statement
initialization
初始化語句。可寫表達式、賦值語句、變量聲明。數組
condition
循環條件表達式。若是表達式結果爲true
,statement
會被執行。若是表達式結果爲false
,那麼執行流程跳到for
語句結構後面的第一條語句。不寫表達式,就是永遠爲true
。函數
final-expression
每次循環的最後都要執行的表達式。執行時機是在下一次condition
的計算以前。學習
statement
只要condition
的結果爲true
就會被執行的語句。多條語句使用塊語句({...}
)來包含。沒有語句執行,使用空語句(;
)。this
我想輸出五個數字。spa
for (let i = 0; i < 5; i++) console.log(i); /* 0 1 2 3 4 */
另外一種寫法輸出五個數字。可選的三個表達式,多行語句,須要使用{}
包含起來。prototype
for (let i = 0; ; i++) { if (i >= 5) break; console.log(i); } /* 0 1 2 3 4 */
注意,若是不寫條件表達式,就要確保循環體內可以跳出,防止死循環。break
能夠跳出循環。code
for...in
以任意順序遍歷一個對象的可枚舉屬性。對於每一個枚舉的屬性,
...
部分都會被執行。
for (variable in object) {...}
variable
每次迭代的時候,將對象的屬性名分配給變量。對象
object
被迭代枚舉的對象。blog
我想輸出對象裏全部的屬性和值。
let o = { a: 1, b: 2, c: 3 }; for (const v in o) { console.log(`o.${v} = ${o[v]}`); } /* o.a = 1 o.b = 2 o.c = 3 */
能夠看見for...in
把全部的可枚舉屬性都枚舉了出來,v
的類型是String
,因此訪問當前遍歷到的屬性值使用了關聯數組o[v]
的方式。
for...in
在遍歷的時候,是以任意順序遍歷的。
let o = []; o[0] = 1; o['one'] = 2; o[2] = 3; for (const v in o) { console.log(`o[${v}] = ${o[v]}`); } /* o[0] = 1 o[2] = 3 o[one] = 2 */
所以當遇到對迭代訪問順序很重要的數組時,最好用整數索引。
我想累加數組全部的成員。
Array.prototype.age = 97; let o = [1,2]; let sum = 0; for (const v in o) { sum += o[v]; console.log(`o[${v}] = ${o[v]}`); } console.log(`sum = ${sum}`); /* o[0] = 1 o[1] = 2 o[age] = 97 sum = 100 */
很顯然這裏不符合咱們的預期,由於for...in
循環語句將返回全部可枚舉屬性,包括非整數類型的名稱和繼承的那些。還會獲取到原型鏈上的可枚舉屬性。
我只想累加自身全部屬性。
Array.prototype.age = 97; let arr = [1, 2]; let sum = 0; for (const v in arr) { if (arr.hasOwnProperty(v)) { sum += arr[v]; } console.log(`arr[${v}] = ${arr[v]}`); } console.log(`sum = ${sum}`); /* o[0] = 1 o[1] = 2 o[age] = 97 sum = 3 */
若是你只要考慮對象自己的屬性,而不是它的原型,那麼使用Object.getOwnPropertyNames()
或執行Object.prototype.hasOwnProperty()
來肯定某屬性是不是對象自己的屬性(也能使用propertyIsEnumerable
)。
Array.prototype.forEach()
對數組的每一個元素執行一次提供的函數。返回值爲
undefined
。
Array.forEach(callback[, thisArg])
callback
爲數組每一個元素執行的函數,這個函數接受三個參數。
currentValue
數組中正在處理的當前元素值。
index
數組中正在處理的當前元素的索引。
array
forEach()
方法正在操做的數組。
thisArg
可選參數。當執行回調 函數時用做this
的值(參考對象)。
我想輸出全部元素。
function logArrayElements(element, index, array) { console.log(`a[${index}] = ${element}`); } [4, 2, 3].forEach(logArrayElements); /* a[0] = 4 a[1] = 2 a[2] = 3 */
forEcah()
會跳過已經刪除或者爲初始化的項(但不包括那些值爲undefined
的項,例如在稀疏數組上)。
function logArrayElements(element, index, array) { console.log(`a[${index}] = ${element}`); } [4, , 3].forEach(logArrayElements); [1, undefined, 3].forEach(logArrayElements); /* a[0] = 4 a[2] = 3 a[0] = 1 a[1] = undefined a[2] = 3 */
沒有辦法終止會跳出forEcah()
循環,除了拋出一個異常。
function logArrayElements(element, index, array) { console.log(`a[${index}] = ${element}`); break; } [1, 2, 3].forEach(logArrayElements); /* Uncaught SyntaxError: Illegal break statement at Array.forEach (<anonymous>) at <anonymous>:5:11 */
使用return
也沒法停止循環。
使用thisArg
,舉個勉強的例子。經過自定義的add()
方法,計算所添加數組的和sum
和成員數count
。
function Counter() { this.sum = 0; this.count = 0; } Counter.prototype.add = function(array) { array.forEach(function(element) { this.sum += element; ++this.count; }, this); }; let obj = new Counter(); obj.add([1, 3, 5, 7]); console.log(obj.count); // 4 === (1+1+1+1) console.log(obj.sum); // 16 === (1+3+5+7) /* 4 16 */
注意:若是使用箭頭函數表達式傳入函數參數,thisArg
參數會被忽略,由於箭頭函數在詞法上綁定了this
值。
若是數組在迭代時被修改了,則其餘元素會被跳過。
let words = ["one", "two", "three", "four"]; words.forEach(function(word) { console.log(word); if (word === "two") { words.shift(); } }); /* one two four */
當到達包含值"two"
的項時,整個數組的第一個項被移除了,這致使全部剩下的項前移了一個位置。由於元素"four"
如今在數組更前的位置,"three"
會被跳過。forEach()
不會在迭代以前建立數組的副本。
for...of
for...of
語句在能夠迭代的對象(Array
、Map
、Set
、String
、TypedArray
、arguments
對象等等)上建立一個迭代循環,調用自定義迭代鉤子,併爲每一個不一樣屬性的值執行語句。
for (variable of iterable) { ... }
variable
在每次迭代中,將不一樣屬性的值分配給變量。
iterable
被迭代枚舉其屬性的對象。
Array
let a = [10, 20, 30]; for (let v of a) { console.log(v); } /* 10 20 30 */
String
let s = 'Tang'; for (let v of s) { console.log(v); } /* T a n g */
arguments
(function() { for (let v of arguments) { console.log(v); } } )(1, 2, 3); /* 1 2 3 */
不管是for...in
仍是for...of
語句都是迭代一些東西。它們之間的主要區別在於它們的迭代方式。
for...in
語句以原始插入順序迭代對象的可枚舉屬性。
for...of
語句遍歷可迭代對象定義要迭代的數據。
如下示例顯示了與Array
一塊兒使用時,for...of
循環和for...in
循環之間的區別。
Object.prototype.objCustom = function() {}; Array.prototype.arrCustom = function() {}; let iterable = [3, 5, 7]; iterable.foo = 'hello'; for (let i in iterable) { console.log(i); } /* 0 1 2 foo arrCustom objCustom */ for (let i in iterable) { if (iterable.hasOwnProperty(i)) { console.log(i); } } /* 0 1 2 foo */ for (let i of iterable) { console.log(i); } /* 3 5 7 */