Javascript数组和对象遍历
一、数组遍历
1. for循环
该方法和方法3比较像,是有序的,不会忽略空元素。
let list = ['a', 'b', 'c', 'd']
list[4] = 'e'
list[10] = 'z'
list['a'] = 0
for (let idx = 0, len = list.length; idx < len; idx++) {
console.log(idx, list[idx])
}
2. for…in[ES5]
for…in其实是对象的遍历方式,并不是数组专有,使用for…in将循环遍历对象本身的所有可枚举属性,以及对象从其构造函数原型中继承的属性,其遍历顺序与Object.keys()函数取到的列表一致。(可枚举-原型)
该方法会遍历数组中非数字下标的元素,会忽略空元素:
let list = [7, 5, 2, 3]
list[10] = 1
list['a'] = 1
console.log(JSON.stringify(Object.keys(list)))
for (let key in list) {
console.log(key, list[key])
}
3. Array.prototype.forEach() [ES5]
鉴于 for 和 for-in 都不特别适合在数组上循环,因此在 ECMAScript 5 中引入了一个辅助方法:Array.prototype.forEach():
forEach遍历数组会按照数组下标升序遍历,并且会忽略空元素:
let list = ['a', 'b', 'c', 'd']
list[4] = 'e'
list[10] = 'z'
list['a'] = 0
list.forEach((value, key, list) => {
console.log(key, value)
})
4. for…of[ES6]
用于可迭代对象的迭代,用来遍历数组是有序的,并且迭代的是数组的值。
该方法不会遍历非数字下标的元素,同时不会忽略数组的空元素:
let list = [7, 5, 2, 3]
list[5] = 4
list[4] = 5
list[10] = 1
// 此时下标6、7、8、9为空元素
list['a'] = 'a'
for (let value of list) {
console.log(value)
}
主要来遍历可迭代的对象(包括Array, Map, Set, arguments等),它主要用来获取对象value值,而for…in主要获取对象key值。
另外:可以由break, continue, throw 或return终止。在这些情况下,迭代器关闭。
二、利用高阶函数遍历数组
1. map[ES5]
map() 方法参数与forEach完全相同,二者区别仅仅在于map会将回调函数的返回值收集起来产生一个新数组。
比如将数组中每个元素的2倍输出为一个新数组:
let list = [1, 2, 3, 4]
let result = list.map((value, idx) => value * 2)
console.log(result) // 输出[2,4,6,8]
2. filter[ES5]
filter() 参数与forEach完全一致,不过它的callback函数应该返回一个真值或假值。filter() 方法创建一个新数组, 新数组包含所有使得callback返回值为真值(Truthy,与true有区别)的元素。
比如过滤数组中的偶数:
let list = [1, 2, 3, 4]
let result = list.filter((value, idx) => value % 2 === 0)
console.log(result) // 输出[2,4]
3. find/findIndex[ES6]
find() 方法返回数组中使callback返回值为Truthy的第一个元素的值,没有则返回undefined。使用非常简单,比如找出数组中第一个偶数:
let list = ['1', '2', '3', '4']
let result = list.find(value => value % 2 === 0)
console.log(result) // 输出 2
findIndex()方法与find方法很类似,只不过findIndex返回使callback返回值为Truthy的第一个元素的索引,没有符合元素则返回-1。比如找出数组中第一个偶数的下标:
let list = [1, 2, 3, 4]
let result = list.findIndex(value => value % 2 === 0)
console.log(result) // 输出 1
4.every/some[ES5]
两个函数接收参数都与以上函数相同,返回都是布尔值。every用于判断是否数组中每一项都使得callback返回值为Truthy,some用于判断是否至少存在一项使得callback元素返回值为Truthy。
let list = [1, 2, 3, 4]
// 判断数组中是否每个元素小于10
let result = list.every(value => {
return value < 10
})
console.log(result) // 输出true
// 判断是否每个元素大于2
result = list.every(value => {
return value > 2
})
console.log(result) // 输出false
// 判断是数组中否存在1
result = list.some(value => {
return value === 1
})
console.log(result) // 输出true
// 判断数组中是否存在大于10的数
result = list.some(value => {
return value > 10
})
console.log(result) // 输出false
5.reduce/reduceRight 累加器
参数与其它函数有所不同:
callback
执行数组中每个值的函数,包含四个参数:
accumulator
累计器累计回调的返回值; 它是上一次调用回调时返回的累积值,或initialValue(见于下方)。
currentValue
数组中正在处理的元素。
currentIndex 可选
数组中正在处理的当前元素的索引。 如果提供了initialValue,则起始索引号为0,否则为1。
array 可选
调用reduce()的数组
initialValue可选
作为第一次调用 callback函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。
reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值,而reduceRight只是遍历顺序相反而已。
比如很常见的一个需求是,把一个如下结构的list变成一个树形结构,使用forEach和reduce可以轻松实现。
列表结构:
let list = [
{
id: 1,
parentId: ''
},
{
id: 2,
parentId: ''
},
{
id: 3,
parentId: 1
},
{
id: 4,
parentId: 2,
},
{
id: 5,
parentId: 3
},
{
id: 6,
parentId: 3
}
]
树形结构:
[
{
"id":1,
"parentId":"",
"children":[
{
"id":3,
"parentId":1,
"children":[
{
"id":5,
"parentId":3
},
{
"id":6,
"parentId":3
}
]
}
]
},
{
"id":2,
"parentId":"",
"children":[
{
"id":4,
"parentId":2
}
]
}
]
利用reduce和forEach实现list转为树形结构:
function listToTree(srcList) {
let result = []
// reduce收集所有节点信息存放在对象中,可以用forEach改写,不过代码会多几行
let nodeInfo = list.reduce((data, node) => (data[node.id] = node, data), {})
// forEach给所有元素找妈妈
srcList.forEach(node => {
if (!node.parentId) {
result.push(node)
return
}
let parent = nodeInfo[node.parentId]
parent.children = parent.children || []
parent.children.push(node)
})
return result
}
二、遍历对象
1. for…in
返回的是所有能够通过对象访问的、可枚举的属性,既包括存在于实例中的属性,也包括存在于原型中的实例,不能保证属性按对象原来的顺序输出。(可枚举-自身-原型)
var obj = {a:1, b:2, c:3};
for (var prop in obj) {
console.log("obj." + prop + " = " + obj[prop]);
}
// Output:
// "obj.a = 1"
// "obj.b = 2"
// "obj.c = 3"
2. Object.keys
用于获取对象自身所有的可枚举的属性值,但不包括原型中的属性,然后返回一个由属性名组成的数组。注意它同for…in一样不能保证属性按对象原来的顺序输出。(可枚举-自身)
// 数组
var arr = ['a', 'b', 'c'];
console.log(Object.keys(arr)); // console: ['0', '1', '2']
// 类数组对象
var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.keys(obj)); // console: ['0', '1', '2']
// 类数组对象-随机下标
var anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.keys(anObj)); // console: ['2', '7', '100']
// 不可枚举属性getFoo
var myObj = Object.create({}, {
getFoo: {
value: function () { return this.foo; }
}
});
myObj.foo = 1;
console.log(Object.keys(myObj)); // console: ['foo']
3. Object.getOwnProperty
如果你想获取一个对象的所有属性,甚至包括不可枚举的,则可用该方法。其返回对象的所有自身属性的属性名组成的数组,但不会获取原型链上的属性。(可枚举&不可枚举-自身)
//获取不可枚举属性
var my_obj = Object.create({}, {
getFoo: {
value: function() { return this.foo; },
enumerable: false
}
});
my_obj.foo = 1;
console.log(Object.getOwnPropertyNames(my_obj).sort()); // ["foo", "getFoo"]
https://segmentfault.com/a/1190000020233039
https://segmentfault.com/a/1190000014497376