這篇文章給大家分享的內容是關於詳解js中的遍歷問題,有著一定的參考價值,有需要的朋友可以參考一下
JavaScript中物件的屬性分為兩種:資料屬性 和 存取器屬性 。
根據特定的上下文環境的不同,又可以將屬性分為: 原型屬性 和實例屬性 。
原型屬性 是定義在物件的原型prototype
中的屬性,
實例屬性 一方面來自建構的函式中,然後就是建構子實例化後所新增的新屬性。
JavaScript中遍歷一個物件的屬性並不太簡單,主要有兩個原因:
#JavaScript中的物件通常都會處在某個原型鏈中,它會從一個或多個的上層原型上繼承一些屬性
JavaScript中的屬性不光有值,它還有一些除了值以外的其他特性,其中一個影響屬性遍歷的特性就是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
特性外的其他特性是否可以被修改。
enumerable
定義了物件的屬性是否可以在for...in
迴圈和Object.keys()
中被列舉。
name、_age擁有'configurable'
、'enumerable'
、'value'
、' writable'
四個屬性描述符,統稱資料描述符
#age擁有'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
的条件下)
for...in...
遍历遍历自身及原型链上所有可枚举的属性
使用 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中的遍历,写的不好多多见谅并指出!
相关推荐:
以上是詳解js中的遍歷 問題的詳細內容。更多資訊請關注PHP中文網其他相關文章!