JS中for...in?和?for...of?的區(qū)別解析
1. 迭代的對(duì)象不同
- for … in 用于迭代對(duì)象的可枚舉字符串屬性,包括自身屬性和繼承的屬性,但不會(huì)遍歷對(duì)象的原型鏈上的 非可枚舉屬性,以及對(duì)象的方法。
從內(nèi)置構(gòu)造函數(shù)(如 Array 和 Object)創(chuàng)建的對(duì)象會(huì)從 Array.prototype 和 Object.prototype 繼承不可枚舉屬性,例如 Array 的 indexOf() 方法或 Object 的 toString() 方法,它們?cè)?for…in 循環(huán)中不會(huì)被訪問(wèn)到。
- for … of 用于迭代可迭代對(duì)象定義的要進(jìn)行迭代的值??傻鷮?duì)象 包括 數(shù)組、字符串、Set、Map等,還包括 arguments 對(duì)象。它遍歷的是可迭代對(duì)象的迭代器(Iterator)返回的值或鍵值對(duì),而不能直接用于普通的對(duì)象。
當(dāng) for…of 循環(huán)迭代一個(gè)可迭代對(duì)象時(shí),它首先調(diào)用可迭代對(duì)象的 @@iterator 方法,該方法返回一個(gè)迭代器,然后重復(fù)調(diào)用生成器的 next() 方法,以生成要分配給 每次循環(huán)迭代的 可迭代對(duì)象 的值的序列。
注意: 每次迭代都會(huì)創(chuàng)建一個(gè)新的變量。在循環(huán)體內(nèi)部重新賦值變量不會(huì)影響可迭代對(duì)象的原始值。
要成為可迭代對(duì)象,必須要有一個(gè)迭代器 @@iterator方法,也就是說(shuō)這個(gè)對(duì)象必須有一個(gè)鍵為@@iterator的屬性,通過(guò)常量 Symbol.iterator 訪問(wèn)這個(gè)屬性,并返回一個(gè)迭代器對(duì)象
迭代器對(duì)象包含一個(gè) next() 方法,無(wú)參數(shù)或者接受一個(gè)參數(shù)的函數(shù),并返回符合 IteratorResult 接口的對(duì)象。
next() 方法會(huì)返回一個(gè)具有 value 和 done 屬性的對(duì)象。
- value 表示當(dāng)前迭代的值。如果迭代器已經(jīng)到達(dá)末尾,那么 value 的值通常為 undefined,但這并不是必然的,具體取決于迭代器的實(shí)現(xiàn)。
- done 是一個(gè)布爾值,表示迭代是否已完成。迭代器是否已完成遍歷。當(dāng)遍歷結(jié)束時(shí),done 為 true,否則為 false。
實(shí)際上,兩者都不是嚴(yán)格要求的;如果返回沒(méi)有任何屬性的對(duì)象,則實(shí)際上等價(jià)于
{ done: false, value: undefined }
。
const obj = { a: 1, b: { h:123 }, }; //定義在自身的屬性 Object.defineProperty(obj, 'c', { value: 3, }); //定義在自身的屬性 Object.defineProperty(obj, 'd', { value: 4, enumerable: true,//是否可枚舉,默認(rèn)false不可枚舉 }); //定義在原型上的屬性 Object.prototype.e=5; for (let key in obj) { console.log(key); // 輸出 'a' 、 'b'、 'd'、'e',但不會(huì)輸出 'c'、'h' } console.log(Object.keys(obj)); // 輸出 ['a', 'b','d'],不包括 'c'、'e'、'h' console.log(Object.getOwnPropertyNames(obj)); // 輸出 ['a', 'b', 'c','d'],包括 'c', 但不包括'e'、'h'
擴(kuò)展:
Object.keys
會(huì)返回一個(gè)包含所有可枚舉的自有字符串屬性的數(shù)組,Object.getOwnPropertyNames
則會(huì)包含所有屬性,包括不可枚舉的。Object.getOwnPropertyDescriptor(obj, prop)
靜態(tài)方法返回一個(gè)對(duì)象,該對(duì)象描述給定對(duì)象上特定屬性(即直接存在于對(duì)象上而不在對(duì)象的原型鏈中的屬性)的配置。
obj
要查找其屬性的對(duì)象。
prop
要檢索其描述的屬性的名稱或 Symbol。
返回值
如果指定的屬性存在于對(duì)象上,則返回其屬性描述符,否則返回 undefined。
// 對(duì)象本身的屬性的屬性描述符 const desc = Object.getOwnPropertyDescriptor(obj, "c"); console.log(desc); // { // value: 3, // writable: false, // enumerable: false, // configurable: false // } // 對(duì)象原型上的屬性的屬性描述符 const desc1 = Object.getOwnPropertyDescriptor(Object.prototype, "e"); console.log(desc1); //{ // value: 5, // writable: true, // enumerable: true, // configurable: true // }
屬性描述符
- value
與屬性關(guān)聯(lián)的值(僅限數(shù)據(jù)描述符)。
- writable :是否可更改
當(dāng)且僅當(dāng)與屬性關(guān)聯(lián)的值可以更改時(shí),為 true(僅限數(shù)據(jù)描述符)。
- enumerable : 是否可枚舉
當(dāng)且僅當(dāng)此屬性在相應(yīng)對(duì)象的屬性枚舉中出現(xiàn)時(shí),為 true。
- configurable :是否可刪除
當(dāng)且僅當(dāng)此屬性描述符的類型可以更改且該屬性可以從相應(yīng)對(duì)象中刪除時(shí),為 true。
在迭代 Array 時(shí),for…of 循環(huán)和 for…in 循環(huán)之間的區(qū)別。
Object.prototype.objCustom = function () {}; Array.prototype.arrCustom = function () {}; const iterable = [3, 5, 7]; iterable.foo = "hello"; for (const i in iterable) { console.log(i); } // "0"、"1"、"2"、"foo"、"arrCustom"、"objCustom" for (const i in iterable) { if (Object.hasOwn(iterable, i)) { console.log(i); } } // "0" "1" "2" "foo" for (const i of iterable) { console.log(i); } // 3 5 7
使用 Object.hasOwn()
來(lái)檢查找到的可枚舉屬性是否為對(duì)象的自有屬性,即非繼承屬性。
const arr=['A','B', ,'D', ,'F']; for(const key in arr){ console.log(key); //0,1,3,5 } for(const item of arr){ console.log(item); // A,B,undefined,D,undefined,F }
for…in 使用屬性枚舉而不是數(shù)組的迭代器。在稀疏數(shù)組中,for…of 會(huì)訪問(wèn)空槽,但 for…in 不會(huì)訪問(wèn)空槽。
2. 遍歷順序
- for … in 循環(huán)遍歷對(duì)象屬性時(shí),遍歷的順序是不確定的,因?yàn)閷?duì)象屬性沒(méi)有固定的順序。
根據(jù)現(xiàn)代 ECMAScript 規(guī)范的定義,遍歷的順序是一致且可預(yù)測(cè)的。在原型鏈的每個(gè)組件中,所有非負(fù)整數(shù)鍵(可以作為數(shù)組索引)將首先按值升序遍歷,然后是其他字符串鍵按屬性創(chuàng)建的先后順序升序遍歷。
- for … of 循環(huán)遍歷可迭代對(duì)象時(shí),遍歷的順序是按照對(duì)象的迭代器定義的順序進(jìn)行的。
3. 可迭代性要求
- for … in 循環(huán)不需要對(duì)象滿足可迭代性要求。
- for … of 循環(huán)要求被遍歷的對(duì)象必須是可迭代對(duì)象(實(shí)現(xiàn)了迭代器接口)。如果對(duì)象沒(méi)有迭代器接口,嘗試使用 for … of 循環(huán)會(huì)拋出錯(cuò)誤。
總的來(lái)說(shuō):
- for…in 循環(huán)用于迭代對(duì)象的可枚舉字符串屬性,包括自身屬性和繼承的屬性,
- for…of 循環(huán)用于迭代可迭代對(duì)象定義的要進(jìn)行迭代的值。
到此這篇關(guān)于JS中for...in 和 for...of 的區(qū)別的文章就介紹到這了,更多相關(guān)js for...in 和 for...of 區(qū)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 全面解析JavaScript里的循環(huán)方法之forEach,for-in,for-of
- 詳解Js里的for…in和for…of的用法
- js遍歷詳解(forEach, map, for, for...in, for...of)
- js中forEach,for in,for of循環(huán)的用法示例小結(jié)
- js中for-in和for-of的區(qū)別詳解
- JavaScript 中for/of,for/in 的詳細(xì)介紹
- JavaScript中for-in和for-of的不同之處及如何正確使用
- JS中for,for...in,for...of和forEach的區(qū)別和用法實(shí)例
- JavaScript中for of和for in的區(qū)別詳解
- JavaScript中for in和for of的區(qū)別示例詳解
相關(guān)文章
通過(guò)微信公眾平臺(tái)獲取公眾號(hào)文章的方法示例
這篇文章主要介紹了通過(guò)微信公眾平臺(tái)獲取公眾號(hào)文章的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12javascript學(xué)習(xí)隨筆(使用window和frame)的技巧
javascript學(xué)習(xí)隨筆(使用window和frame)的技巧...2007-03-03基于JavaScript實(shí)現(xiàn)快速轉(zhuǎn)換文本語(yǔ)言(繁體中文和簡(jiǎn)體中文)
這篇文章主要介紹了基于JavaScript實(shí)現(xiàn)快速切換正體中文和簡(jiǎn)體中文,需要的朋友可以參考下2016-03-03js動(dòng)態(tài)創(chuàng)建及移除div的方法
這篇文章主要介紹了js動(dòng)態(tài)創(chuàng)建及移除div的方法,涉及javascript針對(duì)頁(yè)面元素的動(dòng)態(tài)操作技巧,需要的朋友可以參考下2015-06-06js+css3實(shí)現(xiàn)簡(jiǎn)單時(shí)鐘特效
這篇文章主要為大家詳細(xì)介紹了js+css3實(shí)現(xiàn)簡(jiǎn)單時(shí)鐘特效,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-09-09關(guān)于TypeScript開發(fā)的6六個(gè)實(shí)用小技巧分享
TypeScript是Javascrip t超集,支持靜態(tài)類型檢測(cè),可以在編譯期提前暴露問(wèn)題,節(jié)省debug時(shí)間,下面這篇文章主要給大家介紹了關(guān)于TypeScript開發(fā)的6六個(gè)實(shí)用小技巧,需要的朋友可以參考下2021-09-09js點(diǎn)擊返回跳轉(zhuǎn)到指定頁(yè)面實(shí)現(xiàn)過(guò)程
這篇文章主要為大家詳細(xì)介紹了js點(diǎn)擊返回跳轉(zhuǎn)到指定頁(yè)面實(shí)現(xiàn)過(guò)程,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-04-04