JS中for...in?和?for...of?的區(qū)別解析
1. 迭代的對象不同
- for … in 用于迭代對象的可枚舉字符串屬性,包括自身屬性和繼承的屬性,但不會遍歷對象的原型鏈上的 非可枚舉屬性,以及對象的方法。
從內(nèi)置構(gòu)造函數(shù)(如 Array 和 Object)創(chuàng)建的對象會從 Array.prototype 和 Object.prototype 繼承不可枚舉屬性,例如 Array 的 indexOf() 方法或 Object 的 toString() 方法,它們在 for…in 循環(huán)中不會被訪問到。
- for … of 用于迭代可迭代對象定義的要進(jìn)行迭代的值。可迭代對象 包括 數(shù)組、字符串、Set、Map等,還包括 arguments 對象。它遍歷的是可迭代對象的迭代器(Iterator)返回的值或鍵值對,而不能直接用于普通的對象。
當(dāng) for…of 循環(huán)迭代一個(gè)可迭代對象時(shí),它首先調(diào)用可迭代對象的 @@iterator 方法,該方法返回一個(gè)迭代器,然后重復(fù)調(diào)用生成器的 next() 方法,以生成要分配給 每次循環(huán)迭代的 可迭代對象 的值的序列。
注意: 每次迭代都會創(chuàng)建一個(gè)新的變量。在循環(huán)體內(nèi)部重新賦值變量不會影響可迭代對象的原始值。
要成為可迭代對象,必須要有一個(gè)迭代器 @@iterator方法,也就是說這個(gè)對象必須有一個(gè)鍵為@@iterator的屬性,通過常量 Symbol.iterator 訪問這個(gè)屬性,并返回一個(gè)迭代器對象
迭代器對象包含一個(gè) next() 方法,無參數(shù)或者接受一個(gè)參數(shù)的函數(shù),并返回符合 IteratorResult 接口的對象。
next() 方法會返回一個(gè)具有 value 和 done 屬性的對象。
- value 表示當(dāng)前迭代的值。如果迭代器已經(jīng)到達(dá)末尾,那么 value 的值通常為 undefined,但這并不是必然的,具體取決于迭代器的實(shí)現(xiàn)。
- done 是一個(gè)布爾值,表示迭代是否已完成。迭代器是否已完成遍歷。當(dāng)遍歷結(jié)束時(shí),done 為 true,否則為 false。
實(shí)際上,兩者都不是嚴(yán)格要求的;如果返回沒有任何屬性的對象,則實(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',但不會輸出 '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
會返回一個(gè)包含所有可枚舉的自有字符串屬性的數(shù)組,Object.getOwnPropertyNames
則會包含所有屬性,包括不可枚舉的。Object.getOwnPropertyDescriptor(obj, prop)
靜態(tài)方法返回一個(gè)對象,該對象描述給定對象上特定屬性(即直接存在于對象上而不在對象的原型鏈中的屬性)的配置。
obj
要查找其屬性的對象。
prop
要檢索其描述的屬性的名稱或 Symbol。
返回值
如果指定的屬性存在于對象上,則返回其屬性描述符,否則返回 undefined。
// 對象本身的屬性的屬性描述符 const desc = Object.getOwnPropertyDescriptor(obj, "c"); console.log(desc); // { // value: 3, // writable: false, // enumerable: false, // configurable: false // } // 對象原型上的屬性的屬性描述符 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)對象的屬性枚舉中出現(xiàn)時(shí),為 true。
- configurable :是否可刪除
當(dāng)且僅當(dāng)此屬性描述符的類型可以更改且該屬性可以從相應(yīng)對象中刪除時(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()
來檢查找到的可枚舉屬性是否為對象的自有屬性,即非繼承屬性。
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 會訪問空槽,但 for…in 不會訪問空槽。
2. 遍歷順序
- for … in 循環(huán)遍歷對象屬性時(shí),遍歷的順序是不確定的,因?yàn)閷ο髮傩詻]有固定的順序。
根據(jù)現(xiàn)代 ECMAScript 規(guī)范的定義,遍歷的順序是一致且可預(yù)測的。在原型鏈的每個(gè)組件中,所有非負(fù)整數(shù)鍵(可以作為數(shù)組索引)將首先按值升序遍歷,然后是其他字符串鍵按屬性創(chuàng)建的先后順序升序遍歷。
- for … of 循環(huán)遍歷可迭代對象時(shí),遍歷的順序是按照對象的迭代器定義的順序進(jìn)行的。
3. 可迭代性要求
- for … in 循環(huán)不需要對象滿足可迭代性要求。
- for … of 循環(huán)要求被遍歷的對象必須是可迭代對象(實(shí)現(xiàn)了迭代器接口)。如果對象沒有迭代器接口,嘗試使用 for … of 循環(huán)會拋出錯(cuò)誤。
總的來說:
- for…in 循環(huán)用于迭代對象的可枚舉字符串屬性,包括自身屬性和繼承的屬性,
- for…of 循環(huán)用于迭代可迭代對象定義的要進(jìn)行迭代的值。
到此這篇關(guān)于JS中for...in 和 for...of 的區(qū)別的文章就介紹到這了,更多相關(guān)js for...in 和 for...of 區(qū)別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- JavaScript使用?for...in?、?for...of?或者?forEach()?遍歷元素的示例
- JavaScript中的for...of和for...in循環(huán)容易遇到的問題及解決方法總結(jié)
- JavaScript中for...in、for...of和for await...of迭代方式
- JS中for,for...in,for...of和forEach的區(qū)別和用法實(shí)例
- JavaScript中三種for循環(huán)語句的使用總結(jié)(for、for...in、for...of)
- js遍歷詳解(forEach, map, for, for...in, for...of)
相關(guān)文章
微信小程序?qū)崿F(xiàn)訂單倒計(jì)時(shí)
這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)訂單倒計(jì)時(shí),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-06-06微信小程序配置視圖層數(shù)據(jù)綁定相關(guān)示例
這篇文章主要為大家介紹了微信小程序配置視圖層數(shù)據(jù)綁定相關(guān)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪<BR>2022-04-04Javascript 類型轉(zhuǎn)換、封閉函數(shù)及常見內(nèi)置對象操作示例
這篇文章主要介紹了Javascript 類型轉(zhuǎn)換、封閉函數(shù)及常見內(nèi)置對象操作,結(jié)合實(shí)例形式分析了JavaScript類型顯示轉(zhuǎn)換、隱式轉(zhuǎn)換、變量作用域、封閉函數(shù)及常用內(nèi)置對象相關(guān)操作技巧,需要的朋友可以參考下2019-11-11超實(shí)用的javascript時(shí)間處理總結(jié)
在大家日常開發(fā)中常常會要對時(shí)間進(jìn)行處理,以達(dá)到大家想要的效果,所以本文整理了一些javascript常用的時(shí)間處理類,有需要的可以參考借鑒。2016-08-08談?wù)勎覍avaScript中typeof和instanceof的深入理解
這次主要說說javascript的類型判斷函數(shù)typeof和判斷構(gòu)造函數(shù)原型instanceof的用法和注意的地方,對本文感興趣的朋友一起看看吧2015-12-12