filter() sort()取最大值
实现匹配确定数值对应费率
近日写项目遇到这样的需求:
根据后端传过来的不同数量对应的费率,在用户点击数量更改时显示相应的折扣后金额。
- 关于项目
- 1 技术栈:vue
- 实现
- 首先考虑的是在用户点击改变折扣费率,
- data中存储从后台获取的折扣列表rateList
数据结构(示例):
[
{id: 1, power: 4, rate: 0.99},
{id: 2, power: 8, rate: 0.98},
{id: 3, power: 2, rate: 0.995},
{id: 4, power: 16, rate: 0.96},
]
方法一
采用数组的filter()
方法
没有处理后端返回数据方式(由于公司后端返回数据按照数量排序,前端可以不做排序处理)
getCurrentRate(v) {
let arr = this.rate.filter((item, index) => {
return v >= item.power
})
let len = arr.length-1
this.currentRate = arr[len]? arr[len].rate:1
},
以上每次value改变的时候过滤数组,返回值小于等于当前的数组,那么过滤后数组的最后一位就是当前的折扣费率,同时也要考虑到没有匹配的情况下做初始处理,至此实现。
但上述方法问题:
filter()
方法 数组中的每个元素都会执行传入的函数,一定程度上会造成浪费- 虽然后端处理了返回的数据,但是我觉得从严谨的角度来讲,还是需要前端做一下数据的处理,首先想到了数组的
sort
方法进行排序,虽然this.rate
是一个数组,但是每一项其实是一个对象,sort()
方法是否可以对于数组中对象的某一项按照一定规则进行排序?肯定是可以的。
sort(fn),fn函数可以返回一个按照特定属性进行排序
let arr = [
{id: 1, power: 4, rate: 0.99},
{id: 2, power: 8, rate: 0.98},
{id: 3, power: 2, rate: 0.995},
{id: 4, power: 16, rate: 0.96},
]
let compare = function (cls) {
return function (a, b) {
return b[cls] - a[cls]
}
}
let arrNew = arr.sort(compare('rate'))
console.log(arrNew)
方法二
对于排序后数组依次循环对比,一旦小于rate,返回当前rate的上一个值即为当前的rate,并结束当前循环
let currentRate = null//当前折扣
let count = 9 //当前数量
let index = null //对应索引
let getCurrentRate = (count)=>{
for (let i of arrNew) {
if (count < arr[i].power) {
index = i-1
break
}
}
currentRate = index >= 0 ? arr[index].rate : 1
}
getCurrentRate(count)
for循环以及reduce()对比
for in
for in
可以对Array以及Object循环,可以得到对应的index 以及key 只能遍历“可枚举的属性”
每次迭代操作会同时搜索实例或者原型属性,因此要比其他循环类型慢,一般速度为其他类型循环的 1/7。因此,除非明确需要迭代一个属性数量未知的对象,否则应避免使用 for-in 循环。
- 打印一个数组会发现数组会有个length属性 (不可枚举)
- 对于数组,
index
其实是其一个属性,类型是string
。假如为数组赋值一个属性,使用for in
循环也可以遍历这个属性,因此建议使用for of
遍历数组
数组
let array1 = ['1','3']
array1.name = 'xh'
for(let k in array1){
console.log(k) //1 3 xh
console.log(typeof k)//string
}
对象
let obj = {name:'xm',age:'18'}
for(k in obj){
console.log(k) //name age
console.log(obj[k]) //xm 18
}
- 另外 for in只可遍历数组存在部分,而for循环则会从头遍历,所以如果对for in 循环处理 效率会提高
let arr1 = []
arr1[3] = 'a'
arr1[100] = 'b'
arr1[300] = 'c'
let counts = 0
for(let i = 0;i < arr1.length; i++){
counts++;
console.log(arr1[i])//依次输出,未定义的输出undefined
}
console.log(counts)//301
let arr1 = []
arr1[3] ='a'
arr1[100] ='b'
arr1[300] ='c'
let counts = 0
for(i in arr1){
counts++;
console.log(arr1[i])//a b c
}
console.log(counts)//3
改造后:
let arr1 = []
arr1.name = 'xm'
arr1[3] = 'a'
arr1[100] = 'b'
arr1[300] = 'c'
let counts = 0
for(i in arr1){
counts++
if (arr1.hasOwnProperty(i) && /^0$|^[1-9]\d*$/.test(i) && i <= 4294967294){
console.log(arr1[i])
}
}
console.log(counts)
for of
for of
数组循环可以得到value 不可以对Object循环,而且不会遍历其自定义属性
let array1 = ['1','3']
array1.name = 'xh'
for(let k of array1){
console.log(k) //1 3
}
为什么要引进 for-of?
forEach 不能 break 和 return;
for-in 缺点更加明显,它不仅遍历数组中的元素,还会遍历自定义的属性,甚至原型链上的属性都被访问到。而且,遍历数组元素的顺序可能是随机的。
所以,鉴于以上种种缺陷,我们需要改进原先的 for 循环。但 ES6 不会破坏你已经写好的 JS 代码。目前,成千上万的 Web 网站依赖 for-in 循环,其中一些网站甚至将其用于数组遍历。如果想通过修正 for-in 循环增加数组遍历支持会让这一切变得更加混乱,因此,标准委员会在 ES6 中增加了一种新的循环语法来解决目前的问题,即 for-of 。
那 for-of 到底可以干什么呢?
跟 forEach 相比,可以正确响应 break, continue, return。
for-of 循环不仅支持数组,还支持大多数类数组对象,例如 DOM nodelist 对象。
for-of 循环也支持字符串遍历,它将字符串视为一系列 Unicode 字符来进行遍历。
for-of 也支持 Map 和 Set (两者均为 ES6 中新增的类型)对象遍历。
总结一下,for-of 循环有以下几个特征:
这是最简洁、最直接的遍历数组元素的语法。
这个方法避开了 for-in 循环的所有缺陷。
与 forEach 不同的是,它可以正确响应 break、continue 和 return 语句。
其不仅可以遍历数组,还可以遍历类数组对象和其他可迭代对象。
但需要注意的是,for-of循环不支持普通对象,但如果你想迭代一个对象的属性,你可以用
for-in 循环(这也是它的本职工作)。
https://blog.csdn.net/ZGhekuiwu/article/details/53728607?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2allfirst_rank_v2~rank_v25-5-53728607.nonecase&utm_term=reduce%E5%92%8Cfor%E5%BE%AA%E7%8E%AF%E7%9B%B8%E6%AF%94%E8%B0%81%E8%BF%90%E8%A1%8C%E6%9B%B4%E5%BF%AB
forEach()
还是上面的例子
let arr1 = []
arr1.name = 'xm'
arr1[3] = 'a'
arr1[100] = 'b'
arr1[300] = 'c'
let counts = 0
arr1.forEach((item, index) => {
console.log(item)//a b c
counts++
})
console.log(counts)//3
这里的 index 是 Number 类型,并且也不会像 for-in 一样遍历原型链上的属性。
所以,使用 forEach 时,我们不需要专门地声明 index 和遍历的元素,因为这些都作为回调函数的参数。
forEach 将会遍历数组中的所有元素 return 以及break(报错) 无效
let arr1 = []
arr1.name = 'xm'
arr1[3] = 'a'
arr1[100] = 'b'
arr1[300] = 'c'
let counts = 0
arr1.forEach((item, index) => {
counts++
return item == 'a'
})
console.log(counts)//3
every: 循环在第一次 return false 后返回
some: 循环在第一次 return true 后返回
filter: 返回一个新的数组,该数组内的元素满足回调函数
map: 将原数组中的元素处理后再返回
reduce: 对数组中的元素依次处理,将上次处理结果作为下次处理的输入,最后得到最终结果。