遍歷對象是日常工做中很常見的一個操做,幾乎是平常操做,可是遍歷對象真的是一件很容易的事情麼,顯然不是的。javascript
for (variable in object) {...}
java
這個是一個很常見的用法,相信每一個人順手均可以寫出來。可是這裏須要主要的是一段這個遍歷的定義es6
for...in語句以任意順序遍歷一個對象自有的、繼承的、可枚舉的、非Symbol的屬性。對於每一個不一樣的屬性,語句都會被執行。
一個一個詞摳吧。數組
若是一個key是對象自有的那麼必定能夠用obj.hasOwnProperty(prop)的返回值來判斷函數
這個也很好理解,好比下面的例子this
var parent = {a: 1}; function child() { this.b = 'b'; } child.prototype = parent; var obj = new child();
此時因爲obj的原型鏈繼承了parent,因此其實obj是有a屬性的。換句話說for in會遍歷對象原型鏈上的屬性prototype
什麼是可枚舉的詳細的能夠看一下這個連接
首先對象的屬性分爲兩種,數據屬性如a['b']=1,這個就是數據屬性,另外一種就是訪問器屬性,也就是咱們用的getter。
這兩種屬性都有一個特性的[[Enumerable]],這個布爾值表明了這個屬性是否能夠被枚舉。若是一個對象的屬性被設定爲不可枚舉,那麼for in並不能夠遍歷到。可枚舉性能夠用propertyIsEnumerable來判斷。code
Symbol是什麼這裏不展開說了不熟悉的建議看一下es6 symbol
symbol能夠被用做給某個對象作私有屬性,而若是屬性值是symbol類型的那麼for in也是沒法遍歷的。對象
綜上能夠明確的知道到底對象的哪些屬性能夠用for in去遍歷出來了,坑點在基礎和可枚舉。數組遍歷咱們會天然的去用for in,可是你們是否考慮過,數組也是一個對象,爲何咱們再用for in的時候不會把數組的長度,length做爲一個屬性遍歷到呢,緣由也就是length屬性實際上是一個不可枚舉屬性繼承
Object.keys() 方法會返回一個由一個給定對象的自身可枚舉屬性組成的數組,數組中屬性名的排列順序和使用 for...in 循環遍歷該對象時返回的順序一致。
注意點這裏和for in有一個很大的區別,就是這個返回的是對象自身可枚舉屬性組成的數組,不包含繼承
var parent = {a: 1}; function child() { this.b = 'b'; } child.prototype = parent; var obj = new child(); Object.keys(obj); //['b']
getOwnPropertyNames方法返回一個由指定對象的全部自身屬性的屬性名(包括不可枚舉屬性但不包括Symbol值做爲名稱的屬性)組成的數組。
getOwnPropertySymbols方法返回一個給定對象自身的全部 Symbol 屬性的數組。
關鍵詞,全部的,自身的。這兩個方法不受是否可枚舉屬性的限制,並且是隻返回自身的,因此Object.getOwnPropertyNames的返回值必定是包含了Object.keys的返回值
Reflect.ownKeys 方法返回一個由目標對象自身的屬性鍵組成的數組。它的返回值等同於Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))。
接下來講說另外一種遍歷的方案。for of 與for in 不一樣的就是for of是在可迭代對象(包括 Array,Map,Set,String,TypedArray,arguments 對象等等)上建立一個迭代循環,調用自定義迭代鉤子,併爲每一個不一樣屬性的值執行語句。下面仍是進入摳關鍵詞的階段
什麼是可迭代對象?遵循有可迭代協議的對象成爲可迭代對象,用人話說就是一個對象若是有[Symbol.iterator],那麼他就是可迭代對象。Symbol.iterator是es6提供了 1個內置的 Symbol 值。
iterator簡單說就是一個有一個next函數,這個函數執行的返回值必定是一個對象,對象有兩個屬性done標記迭代是否結束,value標記此次迭代的結果值。
綜上所述也就是說給你的要遍歷的對象增長一個Symbol.iterator就能夠了
除了上面說的還想再補充一種遍歷的場景,對象的拓展運算符,那麼對象的拓展運算符到底是有哪些屬性能夠被賦值。
自身的,可枚舉的。能夠看兩個例子
var obj = {} Object.defineProperty(obj, 'key', { enumerable: false, configurable: true, writable: true, value: "a" }); b = {...obj}; console.log(b); //{}
能夠看到不可枚舉屬性在解構賦值中是不可被賦值的。
var parent = {a: 1}; function child() { this.b = 'b'; } child.prototype = parent; var obj = new child(); var b = {...obj}; console.log(b);//{b: 'b'}
能夠看到繼承的屬性在解構賦值中是不可被賦值的。
對象的遍歷方法不少,可是要根據具體對象屬性的特徵和應用場景,還有兼容性來選擇最適合的遍歷方案。