Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
了方便例子講解,現(xiàn)有數(shù)組和字面量對(duì)象如下
var demoArr = ['Javascript', 'Gulp', 'CSS3', 'Grunt', 'jQuery', 'angular'];
var demoObj = {
aaa: 'Javascript',
bbb: 'Gulp',
ccc: 'CSS3',
ddd: 'Grunt',
eee: 'jQuery',
fff: 'angular'
};
可以直接看示例,用得太多了,很簡(jiǎn)單
(function () {
for (var i = 0, len = demoArr.length; i < len; i++) {
if (i == 2) {
// return; // 函數(shù)執(zhí)行被終止
// break; // 循環(huán)被終止
continue; // 循環(huán)被跳過(guò)
};
console.log('demo1Arr[' + i + ']:' + demo1Arr[i]);
}
})();
關(guān)于for循環(huán),有以下幾點(diǎn)需要注意
var i = 0, len = demo1Arr.length;
for(; i<len; i++) {};
for(var item in arr|obj){} 可以用于遍歷數(shù)組和對(duì)象
(function () {
for (var i in demoArr) {
if (i == 2) {
return; // 函數(shù)執(zhí)行被終止
// break; // 循環(huán)被終止
// continue; // 循環(huán)被跳過(guò)
};
console.log('demoArr[' + i + ']:' + demoArr[i]);
}
console.log('-------------');
})();
for in 本質(zhì)上遍歷的是對(duì)象,之所以能遍歷數(shù)組,是因?yàn)閿?shù)組也是一個(gè)對(duì)象。
var arr = ['react', 'vue', 'angular'];
// 等價(jià)于
var arr = {
0: 'react',
1: 'vue',
2: 'angular'
}
關(guān)于for in,有以下幾點(diǎn)需要注意:
function res() {
var demoArr = ['Javascript', 'Gulp', 'CSS3', 'Grunt', 'jQuery', 'angular'];
for (var item in demoArr) {
if (item == 2) {
return;
};
console.log(item, demoArr[item]);
}
console.log('desc', 'function res'); //不會(huì)執(zhí)行
}
因?yàn)?for in 的目的是為了遍歷對(duì)象,因此在遍歷時(shí),會(huì)同時(shí)搜索該對(duì)象構(gòu)造函數(shù)上的屬性以及原型上的屬性,因此 for in 循環(huán)相對(duì)來(lái)說(shuō)消耗會(huì)更大一點(diǎn)。因此,如果有其他更好的選擇,則盡量避免考慮使用 for in 循環(huán)來(lái)遍歷數(shù)據(jù)。
demoArr.forEach(function(arg) {})
參數(shù)arg表示數(shù)組每一項(xiàng)的元素,實(shí)例如下
demoArr.forEach(function (val, index) {
if (e == 'CSS3') {
return; // 循環(huán)被跳過(guò)
// break; // 報(bào)錯(cuò)
// continue;// 報(bào)錯(cuò)
};
console.log(val, index);
})
具體有以下需要注意的地方
ES5中新增的幾個(gè)數(shù)組方法,forEach, map, filter, reduce等,可以理解為依次對(duì)數(shù)組的每一個(gè)子項(xiàng)進(jìn)行一個(gè)處理(回調(diào)函數(shù)中的操作),他們是對(duì)簡(jiǎn)單循環(huán)的更高一層封裝,因此與單純的循環(huán)在本質(zhì)上有一些不同,所以才會(huì)導(dǎo)致 return, continue, break 的不同。
最重要的一點(diǎn),可以添加第二參數(shù),為一個(gè)數(shù)組,而且回調(diào)函數(shù)中的this會(huì)指向這個(gè)數(shù)組。而如果沒(méi)有第二參數(shù),則this會(huì)指向window。
var newArr = [];
demoArr.forEach(function(val, index) {
this.push(val); // 這里的this指向newArr
}, newArr)
雖然在原生中 forEach 循環(huán)的局限性很多,但是了解他的必要性在于,很多第三方庫(kù)會(huì)擴(kuò)展他的方法,使其能夠應(yīng)用在很多地方,比如 angular 的工具方法中,也有 forEach 方法,其使用與原生的基本沒(méi)有差別,只是沒(méi)有了局限性,可以在IE下使用,也可以遍歷對(duì)象
var result = [];
angular.forEach(demoArr, function(val, index) {
this.push(val);
}, result);
函數(shù)具體的實(shí)現(xiàn)方式如下,不過(guò)有一點(diǎn)值得注意的是,當(dāng)使用 continue時(shí),如果你將 i++ 放在了后面,那么 i++ 的值將一直不會(huì)改變,最后陷入死循環(huán)。因此使用do/while一定要小心謹(jǐn)慎一點(diǎn)。
// 直接使用while
(function () {
var i = 0,
len = demoArr.length;
while (i < len) {
if (i == 2) {
// return; // 函數(shù)執(zhí)行被終止
// break; // 循環(huán)被終止
// continue; // 循環(huán)將被跳過(guò),因?yàn)楹筮叺拇a無(wú)法執(zhí)行,i的值沒(méi)有改變,因此循環(huán)會(huì)一直卡在這里,慎用!!
};
console.log('demoArr[' + i + ']:' + demoArr[i]);
i++;
}
console.log('------------------------');
})();
// do while
(function () {
var i = 0,
len = demo3Arr.length;
do {
if (i == 2) {
break; // 循環(huán)被終止
};
console.log('demo2Arr[' + i + ']:' + demo3Arr[i]);
i++;
} while (i < len);
})();
不建議使用do/while的方式來(lái)遍歷數(shù)組
$.each(demoArr|demoObj, function(e, ele))
可以用來(lái)遍歷數(shù)組和對(duì)象,其中e表示索引值或者key值,ele表示value值
$.each(demoArr, function(e, ele) {
console.log(e, ele);
})
輸出為
0 "Javascript"
1 "Gulp"
2 "CSS3"
3 "Grunt"
4 "jQuery"
5 "angular"
這里有很多需要注意的地方
console.log(this);
//String {0: "C", 1: "S", 2: "S", 3: "3", length: 4, [[PrimitiveValue]]: "CSS3"}
console.log(this == ele);
// true
$.each(this, function(e, ele) {
console.log(e, ele);
})
// 0 c
// 1 s
// 2 s
// 4 3
為什么 length 和 [[PrimitiveValue]]沒(méi)有遍歷出來(lái)?突然靈光一動(dòng),在《javascript高級(jí)編程》中找到了答案,大概意思就是javascript的內(nèi)部屬性中,將對(duì)象數(shù)據(jù)屬性中的 Enumerable 設(shè)置為了false
// 查看length的內(nèi)部屬性
console.log(Object.getOwnPropertyDescriptor(this, 'length'));
// Object {value: 4, writable: false, enumerable: false, configurable: false}
(this)` 與this有所不同,不過(guò)遍歷結(jié)果卻是一樣,你可以在測(cè)試代碼中打印出來(lái)看看
專門用來(lái)遍歷DOMList
$('.list li').each(function (i, ele) {
console.log(i, ele);
// console.log(this == ele); // true
$(this).html(i);
if ($(this).attr('data-item') == 'do') {
$(this).html('data-item: do');
};
})
因?yàn)閐omList并非數(shù)組,而是一個(gè)對(duì)象,只是因?yàn)槠鋕ey值為0,1,2... 而感覺(jué)與數(shù)組類似,但是直接遍歷的結(jié)果如下
var domList = document.getElementsByClassName('its');
for(var item in domList) {
console.log(item, ':' + domList[item]);
}
// 0: <li></li>
// 1: <li></li>
// ...
// length: 5
// item: function item() {}
// namedItem: function namedItem() {}
因此我們?cè)谑褂胒or in 遍歷domList時(shí),需要將domList轉(zhuǎn)換為數(shù)組
var res = [].slice.call(domList);
for(var item in res) {}
類似這樣的對(duì)象還有函數(shù)的屬性 arguments 對(duì)象,當(dāng)然字符串也是可以遍歷的,但是因?yàn)樽址渌麑傩缘?enumerable 被設(shè)置成了false,因此遍歷出來(lái)的結(jié)果跟數(shù)組是一樣的,也就不用擔(dān)心這個(gè)問(wèn)題了.
for of 用于遍歷可迭代對(duì)象「Iterator」。在 JS 中,數(shù)組 Array,字符串 String, Map,Set 等,都是可迭代對(duì)象。
對(duì)象中包含 Symbol.iterator 屬性的,都被稱為可迭代對(duì)象。
var arr = [1, 2, 3];
arr[Symbol.iterator]
// ? values() { [native code] }
簡(jiǎn)單案例。
const iterable = ['react', 'vue', 'angular'];
for (const value of iterable) {
console.log(value);
}
如果你發(fā)現(xiàn)有些人寫函數(shù)這樣搞,不要驚慌,也不要覺(jué)得他高大上鳥(niǎo)不起
+function(ROOT, Struct, undefined) {
...
}(window, function() {
function Person() {}
})
()(), !function() {}() +function() {}() 三種函數(shù)自執(zhí)行的方式
學(xué)習(xí)是一個(gè)艱苦的過(guò)程,當(dāng)然如果能把技術(shù)學(xué)成,最后也一定可以獲得高薪工作。掌握一個(gè)好的學(xué)習(xí)方法,跟對(duì)一個(gè)學(xué)習(xí)的人非常重要。今后要是大家有啥問(wèn)題,可以隨時(shí)來(lái)問(wèn)我,能幫助別人學(xué)習(xí)解決問(wèn)題,對(duì)于自己也是一個(gè)提升的過(guò)程。自己整理了一份2020最全面前端學(xué)習(xí)資料,從最基礎(chǔ)的HTML+CSS+JS到HTML5的項(xiàng)目實(shí)戰(zhàn)的學(xué)習(xí)資料都有整理web前端學(xué)習(xí)干貨,各種框架都有整理,送給每一位前端小伙伴,想要獲取的可以關(guān)注我的頭條號(hào)并在后臺(tái)私信我:前端,即可免費(fèi)獲取
、for...in 語(yǔ)句
1.1 遍歷對(duì)象屬性名稱
for...in 語(yǔ)句常用于遍歷特定對(duì)象的屬性,包括字段名稱屬性及函數(shù)名稱屬性。在JavaScript語(yǔ)言中,它們均稱為屬性 (property)。
let obj = {
name: 'obj',
showName() {
console.log(this.name);
}
};
for (const propName in obj) {
console.log(propName, typeof(obj[propName]));
}
顯示:
name – "string"
showName – "function"
利用這一點(diǎn),可方便地查看特定對(duì)象的所有屬性或方法名稱。下面語(yǔ)句打印出console對(duì)象所有的屬性:
for (const propName in console) {
console.log(propName, typeof(console[propName]));
}
顯示:
debug – "function"
error – "function"
log – "function"
info – "function"
warn – "function"
clear – "function"
...
可以看出,這些屬性全部均是console的函數(shù)名稱,因?yàn)閏onsole沒(méi)有屬性名稱。
1.2 遍歷數(shù)組索引值
for...in 用于數(shù)組中,則遍歷數(shù)組索引值。
let array = ['a', 'b', 'c'];
for (const index in array) {
console.log(index, array[index]);
}
顯示:
0 – "a"
1 – "b"
2 – "c"
1.3 遍歷字符串索引值
由于字符串是由字符組成的數(shù)組,因此 for...in 也可用于遍歷字符串的索引值。
let str = "abc";
for (const index in str) {
console.log(index, str[index]);
}
顯示:
0 – "a"
1 – "b"
2 – "c"
2、for...of 語(yǔ)句
for...of 語(yǔ)句用于遍歷可遍歷對(duì)象 (iterable objects)的元素。這些可遍歷對(duì)象包括字符串、數(shù)組、以及類似于數(shù)組的對(duì)象,這些對(duì)象都帶有l(wèi)ength屬性。
2.1 不能用于遍歷對(duì)象屬性名稱
for...of 語(yǔ)句不能用于遍歷對(duì)象的屬性名稱。因此,下面的代碼是錯(cuò)誤的:
let obj = {
name: 'obj',
showName() {
console.log(this.name);
}
};
for (const propName of obj) {
console.log(propName);
}
顯示:
TypeError: undefined is not a function (near '...propName of obj...')
意為,將 for...of 語(yǔ)句用于對(duì)象上面,無(wú)法提取具體的數(shù)值。
2.2 遍歷數(shù)組元素
for...of 語(yǔ)句經(jīng)常用于遍歷數(shù)組中各元素的數(shù)值。
let arr = [2, 4, 6, 8, 10];
for (const value of arr) {
console.log(value);
}
顯示:
2
4
6
8
10
2.3 遍歷字符串中的字符
由于字符串是由字符組成的數(shù)組,因此 for...of 也可用于遍歷字符串的字符。
let str = "abc";
for (const letter of str) {
console.log(letter);
}
顯示:
a
b
c
2.4 解包
數(shù)組元素如果是帶有特定屬性名稱的對(duì)象,可利用解包性質(zhì)來(lái)快速遍歷這些屬性值。看下面例子。
function Point(x, y) {
return {x:x, y:y};
}
let points = [Point(1, 2), Point(2, 3), Point(4, 5)];
for (const point of points) {
console.log(point.x, point.y);
}
可將Point視為一個(gè)構(gòu)造器 (constructor),每次調(diào)用Point(x, y)都會(huì)創(chuàng)建并返回該類的一個(gè)對(duì)象,且含有x及y的屬性名稱。points則是一個(gè)含有多個(gè)Point對(duì)象的數(shù)組。上面的代碼遍歷出每個(gè)Point對(duì)象后,賦值于point變量,然后打印出它們的x值及y值。
如果我們不希望每次都通過(guò)引用對(duì)象屬性的方式來(lái)訪問(wèn)x及y值,則可編寫代碼如下:
for (const point of points) {
let x = point.x;
let y = point.y;
console.log(x, y);
}
這一步可利用ES6的const解包特性予以簡(jiǎn)化:
for (const point of points) {
const {x, y} = point;
console.log(x, y);
}
更進(jìn)一步,我們可以直接解包:
for (const {x, y} of points) {
console.log(x, y);
}
2.5 遍歷Map
let scoreMap = new Map([
['Mike', 75],
['Tom', 80],
['Smith', 90]
]);
for (const [key, value] of scoreMap) {
console.log(key, value);
}
與上一節(jié)不同的是,Map需要使用 [key, value] 的方式來(lái)解包。
3、forEach 方法
3.1 forEach 常見(jiàn)調(diào)用方式
for...in,for...of 均是語(yǔ)句,與它們不同的是,forEach是數(shù)組的內(nèi)嵌方法。這意味著我們可以直接在數(shù)組對(duì)象上面直接調(diào)用該方法。
let arr = [1, 3, 5, 7, 9];
arr.forEach((element) => {
console.log(element);
});
作為數(shù)組方法,forEach有一個(gè)參數(shù),該參數(shù)的類型是函數(shù),稱為回調(diào)函數(shù) (callback function)。所謂回調(diào)函數(shù),是指一旦程序員提供了這樣的函數(shù),JavaScript引擎將負(fù)責(zé)調(diào)用此函數(shù)。
回調(diào)函數(shù)的價(jià)值在于回調(diào)函數(shù)可能存在多個(gè)參數(shù),而這些參數(shù)將由JavaScript引擎自動(dòng)提供。在回調(diào)函數(shù)中,我們可對(duì)JavaScript引擎所自動(dòng)提供的參數(shù)進(jìn)行進(jìn)一步加工。
在上面的回調(diào)函數(shù)中,element是由JavaScript引擎自動(dòng)提供的,代表每個(gè)數(shù)組元素。
上面的代碼采用了lambda匿名表達(dá)式。它等同于:
let arr = [1, 3, 5, 7, 9];
function callback(element) {
console.log(element);
}
arr.forEach(callback);
可見(jiàn),lambda表達(dá)式更加簡(jiǎn)練。
3.2 forEach 的參數(shù)
forEach共有3個(gè)參數(shù) (上面例子只用了第1個(gè)),它們的排列順序如下:
arr.forEach((element, index, array) => {
console.log(element);
console.log(index);
console.log(array);
});
參數(shù)element是數(shù)組元素,參數(shù)index是數(shù)組元素所在數(shù)組中的索引值,參數(shù)array是整個(gè)數(shù)組。
一般情況下,我們僅需用到element及index參數(shù)就足夠了。由于是每次迭代,因此,forEach方法中的array參數(shù)較少用到。
index每次遍歷時(shí)都會(huì)加1,且每次都會(huì)與array的長(zhǎng)度比較。一旦超出array的界限,就會(huì)終止遍歷。如果遍歷過(guò)程中,修改了array的長(zhǎng)度,則需特別注意這一點(diǎn)。
3.2 forEach 遍歷的終止
如何中止forEach的遍歷?JavaScript并未提供這樣的機(jī)制,但我們可以用一個(gè)雙重嵌套的異常來(lái)終止遍歷。
let arr = [1, 3, 5, 7, 9];
try {
arr.forEach((element, index, array) => {
try {
console.log(index);
if (index >= 3) {
throw new Error('forEach termination signal');
}
} catch (error) {
throw error;
}
});
} catch (e) {
if (e.message === 'forEach termination signal') {
console.log('forEach terminated.');
}
}
console.log('This line of code should be executed.');
顯示:
0
1
2
3
forEach terminated.
This line of code should be executed.
我們?cè)O(shè)定,當(dāng)index的值大于等于3時(shí),需要終止遍歷。這樣,在第7行,當(dāng)此條件滿足時(shí),即拋出"forEach termination signal"的異常。
此時(shí),程序流程轉(zhuǎn)入到第10行至第12行最內(nèi)層的異常捕獲處理代碼:
} catch (error) {
throw error;
}
捕獲異常后,如果我們不重新拋出異常,JavaScript引擎則會(huì)認(rèn)為我們已正確地處理了異常,因此會(huì)恢復(fù)中斷的遍歷進(jìn)程,繼續(xù)處理下一個(gè)數(shù)組元素,這不是我們想要的。因此,我們?cè)诖酥匦聮伋鲈摦惓#郧袑?shí)終止遍歷。
這時(shí),forEach的遍歷因異常而終止,從而達(dá)到了我們的最初的目標(biāo)。但因?yàn)橛挟惓#绻覀兾醋魅魏翁幚恚瑒t該異常會(huì)導(dǎo)致整個(gè)程序都終止運(yùn)行。只有在我們處理了異常后,程序才能往下走。這就是第14行至18行最外層異常捕獲代碼的作用:
} catch (e) {
if (e.message === 'forEach termination signal') {
console.log('forEach terminated');
}
}
先判斷它是不是"forEach termination signal"。如果是,則簡(jiǎn)單地打印一行消息。由于這里未再拋出新的異常,因此JavaScript引擎認(rèn)為我們已經(jīng)正確地處理了異常,則繼續(xù)執(zhí)行后面的代碼。這樣,最后一行第20行語(yǔ)句將被執(zhí)行并打印出"This line of code should be executed."的文本。
一般來(lái)講,如果我們需要在數(shù)組的遍歷過(guò)程中終止遍歷,不要使用 forEach 語(yǔ)句,使用最傳統(tǒng)的方式即可:
let arr = [1, 3, 5, 7, 9];
for (let i = 0; i < arr.length; i++) {
console.log(i, arr[i]);
if (i >= 3) {
break;
}
}
console.log('This line of code should be executed.');
這樣即可在遍歷中訪問(wèn)數(shù)組的索引值與數(shù)組元素,又可以極為方便地隨時(shí)終止遍歷。
使用for-of循環(huán)(ES2015+) - 異步友好
使用forEach/some - 異步不友好(見(jiàn)例子)
使用for - 異步友好
不使用map,除非你用不到循環(huán)的返回值,請(qǐng)注意map和forEach是有區(qū)別的,map主要用來(lái)生成一個(gè)新的數(shù)組。
異步謹(jǐn)慎使用forEach,如果回調(diào)做異步工作,需要forEach等待(但是forEach不會(huì)等待,而是直接到底)。
用法簡(jiǎn)單直接,使用let把單個(gè)變量的范圍進(jìn)行限制,不會(huì)影響到循環(huán)外,而且性能優(yōu)于forEach,建議遍歷數(shù)組使用該函數(shù)。
const a = ["a", "b", "c"];
for (let val of a) {
console.log(val);
}
//依次打印結(jié)果 "a", "b", "c"
同時(shí)也對(duì)異步處理十分友好。
//延時(shí)
function delay(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
//異步函數(shù)打印數(shù)組內(nèi)容
async function show(arr) {
for (let item of arr) {
await delay(400); //等待 forEach 則會(huì)無(wú)視 await
console.log(item);
}
}
show(["頭", "條", "新", "浪", "潮"]);
//依次延時(shí)打印結(jié)果 "頭" "條" "新" "浪" "潮"
處理同步代碼(不需要等待),則可以使用forEach用于在循環(huán)期間完成的異步進(jìn)程。
const a = ["a", "b", "c"];
a.forEach((val) => {
console.log(val);
});
//依次打印結(jié)果 "a", "b", "c"
異步處理例子
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。