prototype
中的屬性,JavaScript中遍歷一個對象的屬性並不太簡單,主要有兩個緣由:es6
Enumerable
(一個屬性描述符) ,若是該值爲 true
,則這個屬性是可枚舉的,不然反之屬性描述符
主要有兩種形式:數據描述符
和存取描述符
。Object.getOwnPropertyDescriptor
與 Object.getOwnPropertyDescriptors
兩個方法獲取對象的屬性描述符
。var obj = { name: '10', _age: 25, get age(){ return this._age; }, set age(age){ if(age<1){ throw new Error('Age must be more than 0'); }else{ this._age = age; } } }; var des = Object.getOwnPropertyDescriptors(obj); console.log(des); /** * des: { * name: { * configurable: true, * enumerable: true, * value: "10", * writable: true, * __proto__: Object * }, * _age: { * configurable: true, * enumerable: true, * value: 25, * writable: true, * __proto__: Object * }, * age: { * configurable: true, * enumerable: true, * get: f age(), * set: f age(age), * __proto__: Object * }, * __proto__: Object * } */
該屬性的值(僅針對數據屬性描述符有效)數組
當writable
屬性設置爲false
時,該屬性被稱爲「不可寫」。它不能被從新分配。瀏覽器
獲取該屬性的訪問器函數(getter
)。若是沒有訪問器, 該值爲undefined
。(僅針對包含訪問器或設置器的屬性描述有效)數據結構
獲取該屬性的設置器函數(setter
)。 若是沒有設置器, 該值爲undefined
。(僅針對包含訪問器或設置器的屬性描述有效)函數
configurable
特性表示對象的屬性是否能夠被刪除,以及除writable
特性外的其餘特性是否能夠被修改。this
enumerable
定義了對象的屬性是否能夠在 for...in
循環和 Object.keys()
中被枚舉。prototype
'configurable'
、'enumerable'
、'value'
、'writable'
四個屬性描述符,統稱數據描述符
'configurable'
、'enumerable'
、'get'
、'set'
四個屬性描述符,統稱存取描述符
分類 | 'configurable' | 'enumerable' | 'value' | 'writable' | 'get' | 'set' |
---|---|---|---|---|---|---|
數據描述符 | yes | yes | yes | yes | no | no |
存取描述符 | yes | yes | no | no | yes | yes |
對象的屬性描述符,能夠經過Object.defineProperty
和Object.defineProperties
來修改(configurable
爲true
的條件下)code
for...in...
遍歷Chrome Opera 的 JavaScript 解析引擎遵循的是新版 ECMA-262 第五版規範。所以,使用 for-in 語句遍歷對象屬性時遍歷書序並不是屬性構建順序。而 IE6 IE7 IE8 Firefox Safari 的 JavaScript 解析引擎遵循的是較老的 ECMA-262 第三版規範,屬性遍歷順序由屬性構建的順序決定。
for-in 語句沒法保證遍歷順序,應儘可能避免編寫依賴對象屬性順序的代碼。若是想順序遍歷一組數據,請使用數組並使用 for 語句遍歷。
var Animal = function({name='none', age=3, weight=80}={}){ this.name = name; this.age = age; this.weight = weight; } Animal.prototype = { color: 'red' } var dog = new Animal() // 將weight屬性設置爲 不可枚舉 Object.defineProperty(dog, 'weight', { enumerable: false }) for(let i in dog){ console.log(n); } //原型鏈上的color一樣被遍歷出來了,而且因爲weight屬性被設置成了enumerable:false,因此不可被遍歷 //name //age //color
for...of
遍歷一個數據結構只要部署了Symbol.iterator
屬性,就被視爲具備 iterator
接口,就能夠用for...of
循環遍歷它的成員。也就是說,for...of
循環內部調用的是數據結構的Symbol.iterator
方法。對象
for...of
循環可使用的範圍包括數組、Set
和 Map
結構、某些相似數組的對象(好比arguments對象、DOM NodeList 對象)、Generator 對象,以及字符串。繼承
若是不太清楚iterator
,請去看看阮一峯大神的這篇文章,裏面關於for...of
以及iterator
都講的很是詳細!
其實for...of
和for...in
都是迭代一些東西,它們之間的主要區別在於它們的迭代方式。
for...in
語句以原始插入順序迭代對象的可枚舉屬性。for...of
語句遍歷可迭代對象定義要迭代的數據。請仔細看如下實例,理解其中的區別
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 }
Object.prototype.objCustom = function() {}; Array.prototype.arrCustom = function() {}; let iterable = [3, 5, 7]; iterable.foo = 'hello';
在這段代碼裏面,因爲繼承和原型鏈,對象iterable
繼承屬性objCustom
和arrCustom
。
for (let i in iterable) { console.log(i); // 0, 1, 2, "foo", "arrCustom", "objCustom" }
在這段代碼裏面,此循環僅以原始插入順序記錄iterable
對象的可枚舉屬性。它不記錄數組元素3, 5, 7
或hello
,由於這些不是枚舉屬性。可是它記錄了數組索引以及arrCustom
和objCustom
(爲什麼記錄arrCustom
和objCustom
在本文for...in
裏面有講過)。
for (let i in iterable) { if (iterable.hasOwnProperty(i)) { console.log(i); // 0, 1, 2, "foo" } }
hasOwnProperty()
用來檢查找到的枚舉屬性是否是對象本身的(便是不是繼承的)
for (let i of iterable) { console.log(i); // 3, 5, 7 }
該循環迭代並記錄iterable做爲可迭代對象定義的迭代值,這些是數組元素 3, 5, 7,而不是任何對象的屬性。
Object.keys
遍歷Object.keys()
方法會返回一個由一個給定對象的自身可枚舉屬性組成的數組,數組中屬性名的排列順序和使用 for...in
循環遍歷該對象時返回的順序一致 (二者的主要區別是 一個 for-in
循環還會枚舉其原型鏈上的屬性)。
Object.getOwnPropertyNames()
遍歷Object.getOwnPropertyNames()
方法返回一個由指定對象的全部自身屬性的屬性名(包括不可枚舉屬性但不包括Symbol值做爲名稱的屬性)組成的數組,此方法不會獲取原型鏈上的屬性。
var Animal = function({name='', age=1, weight=70}={}){ this.name = name; this.age = age; this.weight = weight; } Animal.prototype = { type: 'Animal' } var dog = new Animal() // 將height屬性設置爲 不可枚舉 Object.defineProperty(dog, 'weight', { enumerable: false }) var keys = Object.getOwnPropertyNames(dog); console.log(keys) // ['name', 'age', 'weight']
這篇文章但願能讓你們更加理解js中的遍歷,寫的很差多多見諒並指出!