day _5(4) 案例
案例1 数组去重
*/
var arr = [ 1, 2, 4, 3, 2, 1, 2, 3, 2, 1, 2, 4, 5, 4, 3, 2, 1, 99 ]
console.log('原始数组 : ', arr)
// 1. 排序, 遍历
// arr.sort()
// console.log('排序之后 : ', arr)
// // 遍历数组, 只要前一个和后一个一样, 删除一个
// for (var i = 0; i < arr.length; i++) {
// // 当前这个 arr[i]
// // 下一个 arr[i + 1]
// if (arr[i] === arr[i + 1]) {
// arr.splice(i, 1)
// i--
// }
// }
// console.log('去重之后 : ', arr)
// 2. 第二个循环查找后面有没有长得一样的
// 分析: 第二个循环的目的, 为了找到后续内容中是否有重复的(indexOf)
// for (var i = 0; i < arr.length; i++) {
// // i 当前这个数据的索引
// var repeat = arr.indexOf(arr[i], i + 1)
// // repeat 如果为 -1 说明后面没有了
// if (repeat === -1) continue
// // repeat 如果不为 -1, 那么 repeat 索引位置就是那个重复的数据
// arr.splice(repeat, 1)
// i--
// }
// console.log('去重之后 : ', arr)
// 3. Set
// ES2015 推出的一种数据结构, 特点: 不接受重复数据
// 语法结构创建: new Set([ 数据, 数据, 数据 ])
// var s = new Set([ 10, 20, 30, 10, 20, 30 ])
// console.log(s)
// 3-1. 利用 Set 数据结构把数组内的重复数据摒弃
// var s = new Set(arr)
// // console.log(s)
// // 3-2. 把 s 还原成一个数组
// // 语法: Array.from()
// var r1 = Array.from(s)
// console.log(r1)
// // 语法: ... 运算符
// var r2 = [ ...s ]
// console.log(r2)
// var r1 = [ ...new Set(arr) ]
// var r2 = Array.from(new Set(arr))
// console.log(r1, r2)
// 4. 计数排序的逻辑
// var tmp = []
// for (var i = 0; i < arr.length; i++) {
// var item = arr[i]
// tmp[item] = '随便'
// }
// arr = []
// for (var i = 0; i < tmp.length; i++) {
// if (!tmp[i]) continue
// arr.push(i)
// }
// console.log(arr)
// var tmp = {}
// for (var i = 0; i < arr.length; i++) {
// var item = arr[i]
// tmp[item] = '随便'
// }
// arr = []
// for (var k in tmp) {
// arr.push(k - 0)
// }
// console.log(arr)
// 5. 创建新数组, 依次插入
// var result = []
// for (var i = 0; i < arr.length; i++) {
// var item = arr[i]
// // 判断, 如果 result 内没有 item 这个数据, 才向内插入
// if (result.indexOf(item) === -1) result.push(item)
// }
// console.log('去重之后 : ', result)
案例2 数组常用方法 forEach
- 语法: 数组.forEach(function (item, index, origin) {})
=> item 就是数组内的每一项
=> index 就是数组内每一项的索引
=> origin 就是原始数组 - 返回值: undefined
// 问题: 为什么可以书写 数组.push()
// 私人: JS 的语法内, 设计了一个 "空间", 里面存储了一系列数组方法
// 如果你设计一个方法, 也想 数组.xxx() 的话, 把你设计的方法也放在这个 "空间"
// 空间: Array.prototype
// 添加到 Array.prototype 上的方法, 就是为了给所有的数组使用的
// 当你调用这个方法的时候, 需要用 数组 去调用
// Array.prototype.myPush = function myPush() {
// // 问题1: 向哪一个数组内追加数据
// // 你不确定将来调用你的数据变量名是什么
// // 不能使用一个准确的名字
// // 可以使用一个关键字叫做 this
// // 谁调用的 myPush, this 就是谁
// // console.log(this)
// // 向 this 这个数组内追加数据
// // 问题2: 追加什么数据
// // arguments 内有多少个数据, 向 this 内追加多少个数据
// // 循环遍历 arguments, 为了拿到每一个要追加的数据
// for (var i = 0; i < arguments.length; i++) {
// var item = arguments[i]
// // console.log(item)
// // 把 item 依次追加到 this 里面
// this[this.length] = item
// }
// // 返回值: 追加后最新的长度
// return this.length
// }
// 需求: 自己封装一个 myPush 方法
// 要求: 和 push 方法的 调用方式 / 传递参数 / 返回值 一模一样
// 为了调用方式一样, 我需要把我自己封装的方法放在 Array.prototype 上
// Array.prototype.myPush = function () {
// // 在该函数内, this 关键字表示的就是调用 myPush 方法的数组
// // 在该函数内, arguments 表示的是你传递的所有实参的集合
// // 目的: 把 arguments 内的每一个追加到 this 内
// for (var i = 0; i < arguments.length; i++) {
// this[this.length] = arguments[i]
// }
// // 为了返回值一样
// return this.length
// }
// 我想用这个 myPush 怎么办
// var arr = [ 100, 200, 300 ]
// var res = arr.myPush('新来的', '新来的2')
// console.log('追加之后 : ', arr)
// console.log('返回值 : ', res)
// 需求: 自己封装一个 muUnshift 方法
// 要求: 和数组的 unshift 方法 调用方式 / 传递参数 / 返回值 一模一样
// 把 myUnshift 方法添加到 Array.prototype 上
// Array.prototype.myUnshift = function () {
// // 把 arguments 内的内容给到 this 的最前面
// // 关注原始数组的 length
// var len = this.length
// // 关注要插入多少个数据
// var insertLen = arguments.length
// // 从 this 的最后一个数据开始, 每一个数据向后顺延 insertLen 个索引位置
// // 倒着循环 this, 拿到每一个需要移动的数据
// for (var i = len - 1; i >= 0; i--) {
// this[i + insertLen] = this[i]
// }
// // 把 arguments 内的内容一次添加到 this 内
// // arguments 的索引 就是 this 内数据的索引位置
// for (var i = 0; i < insertLen; i++) {
// this[i] = arguments[i]
// }
// // 制作一个返回值
// return this.length
// }
// var arr = [ 10, 20, 30 ]
// var res = arr.myUnshift('新来的1', '新来的2')
// console.log('插入之后 : ', arr)
// console.log('返回值 : ', res)
// 需求: 封装 myShift 方法
// Array.prototype.myShift = function () {
// // 判断
// if (this.length <= 0) return ''
// // 拿出 this 的 [0] 位置数据
// var data = this[0]
// // 把从 [1] 开始所有的数据直接向前移动
// for (var i = 1; i < this.length; i++) {
// this[i - 1] = this[i]
// }
// this.length--
// // 制作返回值
// return data
// }
// var arr = [ 10, 20, 30 ]
// var res = arr.myShift()
// console.log('插入之后 : ', arr)
// console.log('返回值 : ', res)
// 需求: 封装一个 myForEach 方法, 能帮我自动遍历数组
// 遍历的目的就是为了拿到每一个数据, 想做事
// 把我想做的事情放在一个 函数内, 以回调函数的形式给到 myForEach
// 方法添加到 Array.prototype 上
// Array.prototype.myForEach = function (cb) {
// // 遍历谁 ? this
// for (var i = 0; i < this.length; i++) {
// // 每一个索引 i
// // 每一个数据 this[i]
// // console.log(this[i])
// // 随着循环调用 cb
// // 当你调用 cb 的时候, 把 数组的每一项 内容回传
// cb(this[i], i, this)
// }
// }
// 将来我需要遍历数组的时候
// var arr = [ 100, 200, 300, 400, 500 ]
// 遍历数组: 想做事
// arr.myForEach(function (item, index, origin) {
// console.log('随着循环做点事情', item, index, origin)
// })
// 求和
// var sum = 0
// arr.myForEach(function (item) {
// sum += item
// })
// console.log(sum)
案例3 数组方法 map
- 语法: 数组.map(function (item, index, origin) {})
- 返回值: 根据条件映射出来的新数组
- 注意: 映射条件以 rteurn 的形式书写
// 需求: myMap 方法
// 要求: 根据原始数组 和 我给出的条件, 把 原始数组内的内容 全部修改, 放在一个新数组内返回
// Array.prototype.myMap = function (cb) {
// // 1. 创建一个新数组
// var res = []
// // 2. 想办法向新数组内添加成员
// // 2-1. 遍历原始数组
// for (var i = 0; i < this.length; i++) {
// // 2-2. 逐个向 res 内添加数据
// // 问题: 添加一个什么数据 ?
// // 利用回调函数的返回值, 接受加工结果
// // 当 i === 0 的时候, cb(10, 0), 返回值是 100 赋值给了 r
// // 当 i === 1 的时候, cb(20, 1), 返回值是 200 赋值给了 r
// // 当 i === 2 的时候, cb(30, 2), 返回值是 300 赋值给了 r
// var r = cb(this[i], i, this)
// // 只要随着循环每一次把 r 追加到 res 数组内
// res.push(r)
// }
// // 3. 把新数组返回
// return res
// }
// // 将来使用的时候
// var arr = [ 10, 20, 30 ]
// var res = arr.myMap(function (item, index, origin) {
// // 对每一个数据进行加工
// return item * 100
// })
// console.log(arr)
// console.log(res)
// res === [ 数据, 数据, 数据 ]
/*
数组方法 map
+ 语法: 数组.map(function (item, index, origin) {})
+ 返回值: 根据条件映射出来的新数组
+ 注意: 映射条件以 rteurn 的形式书写
*/
var arr = [ 10, 20, 30 ]
var res = arr.map(function (item, index, origin) {
return item * 100
})
console.log(arr)
console.log(res)
案例4 方法: filter
- 语法: 数组.filter(function (item, index, origin) {})
- 作用: 从原始数组中过滤出满足要求的项, 放在新数组内
- 返回值: 一个新数组, 存储的是原始数组中满足要求的数据
- 注意: 以 return 的形式书写 过滤条件
// var arr = [ 100, 200, 300, 400, 500, 300, 400, 300 ]
// var res = arr.filter(function (item) {
// return item > 300
// })
// console.log(res)
// Array.prototype.myFilter = function (cb) {
// // 1. 准备一个新数组
// var result = []
// // 2. 向 result 内添加数据
// for (var i = 0; i < this.length; i++) {
// var r = cb(this[i], i, this)
// // 当 r 为 true 的时候, 表示当前这一项满足条件, 需要插入到 result 内
// r && result.push(this[i])
// }
// // 3. 返回新数组
// return result
// }
// 使用的时候
// var res = arr.myFilter(function (item) {
// // 以 return 的形式书写条件
// return item > 300
// })
// console.log(res)
// 删除源数组内所有的 300
// arr = arr.myFilter(function (item) { return item !== 300 })
// console.log(arr)
案例5 方法: find()
- 语法: 数组.find(function (item, index, origin) {})
- 返回值: 原始数组内满足条件的第一项
- 注意: 以 return 的形式书写查找条件
// var arr = [
// { id: 1, name: 'Jack' },
// { id: 2, name: 'Rose' },
// { id: 3, name: 'Tom' },
// { id: 2, name: 'Jerry' }
// ]
// // 我只有一个 id 信息
// var id = 2
// // 想从 arr 数组内找到 id 为 2 的数据
// // var user = arr.find(function (item) {
// // // item 是每一项, 每一个 对象 数据类型
// // return item.id === id
// // })
// // console.log(user)
// Array.prototype.myFind = function (cb) {
// // 1. 准备一个变量接受结果
// var res = undefined
// // 2. 从数组内找到对应的数据赋值给 res
// for (var i = 0; i < this.length; i++) {
// var r = cb(this[i], i, this)
// if (r) {
// // 把 this[i] 赋值给 res
// res = this[i]
// break
// }
// }
// // 3. 把 res 当做返回值
// return res
// }
// // 使用的时候
// var res = arr.myFind(function (item) {
// console.log('我执行了')
// return item.id === id
// })
// console.log(res)
// var arr = [
// { id: 1, name: 'Jack' },
// { id: 2, name: 'Rose' },
// { id: 3, name: 'Tom' },
// { id: 2, name: 'Jerry' }
// ]
/*
思考:
+ find 多用于查找 [] 内存储的是复杂数据类型
+ 作用: 根据一个条件找到一条数据
+ 问题: 你为什么要找他 ?
=> 找到这条信息进行 增删改查
+ 如果 find 方法实现的是 深拷贝
=> 你的返回值和数组内的内容是两个 数据结构
=> 当你使用 返回值修改的时候, 数组内的数据不变
+ 最好的方案, 把数组中某一条数据的 地址 拿出来
=> 利用返回值修改的时候, 数组中对应的数据也会改变
*/
// var user = arr.find(function (item) { return item.id === 2 })
// user.name = '张思睿'
// console.log(arr)
案例6 方法: every()
- 语法: 数组.every(function (item, index, origin) {})
- 返回值: 必然是一个 布尔值
=> 如果原始数组中每一个数据都满足条件, 返回的是 true
=> 只要有任何一个不满足条件, 返回值就是 false
var arr = [ 100, 200, 300, 400, 500 ]
// var res = arr.every(function (item) {
// console.log('执行')
// return item < 300
// })
// console.log(res)
// Array.prototype.myEvery = function (cb) {
// // 从一堆内容中, 找到一个不对的, 就可以结束了
// // 1. 假设所有内容全部满足条件
// var flag = true
// // 2. 通过遍历数组来验证我的假设
// for (var i = 0; i < this.length; i++) {
// var r = cb(this[i], i, this)
// if (!r) {
// // 推翻我的假设
// flag = false
// break
// }
// }
// // 3. 返回我的假设
// return flag
// }
// var res = arr.myEvery(function (item) {
// console.log('执行')
// return item < 600
// })
// console.log(res)
案例7 方法: some()
- 语法: 数组.some(function (item, index, origin) {})
- 返回值: 必然是一个布尔值
=> 如果数组中有任意一个满足条件, 最终返回 true
=> 只有数组中所有数据都不满足条件, 最终返回 false
// var arr = [ 100, 200, 300, 400, 500 ]
// // var res = arr.some(function (item) {
// // console.log('执行')
// // return item > 100
// // })
// // console.log(res)
// Array.prototype.mySome = function (cb) {
// // 1. 假设都不满足条件
// var flag = false
// // 2. 开始循环
// for (var i = 0; i < this.length; i++) {
// var r = cb(this[i], i, this)
// if (r) {
// flag = true
// break
// }
// }
// // 3. 定义返回值
// return flag
// }
// var res = arr.mySome(function (item) {
// console.log('执行')
// return item > 1000
// })
// console.log(res)
案例8 方法: reduce()
- 语法: 数组.reduce(function (prev, item, index, origin) {}, init)
=> prev:
-> 循环的第一次表示的是 init 初始值
-> 循环的第二次开始表示的是 上一次的 结果
=> init: 表示叠加的初始值, 选填
-> 如果你填写了 init, 方法内数组遍历的时候, 从 [0] 开始
-> 如果你没有填写 init, 默认使用数组 [0] 数据来充当 init, 方法内遍历的时候从 [1] 开始遍历
var arr = [ 10, 20, 30, 40, 50 ]
console.log('原始数组 : ', arr)
Array.prototype.myReduce = function (cb, init) {
// 1. 决定一个遍历的开始位置
var start = init !== undefined ? 0 : 1
// 2. 判断 init 是否传递了, 来决定使用哪一个当做初始值
init = init ?? this[0]
// 3. 开始遍历
for (var i = start; i < this.length; i++) {
// 本次运算的结果
var r = cb(init, this[i], i, this)
// 修改 init
// 思考: 当你给到回调函数内运算的时候, 把前一次的值, 和本次的值都给了
// 在回调函数内已经进行完毕本次运算了
// r 就是本次运算的结果, 直接替换 init
init = r
}
// 4. 循环结束, init 就是最终结果
return init
}
// 使用的时候
var r1 = arr.myReduce(function (prev, item) {
console.log('prev : ', prev, ' --- ', 'item : ', item)
return prev + item
}, 0)
console.log(r1)
var r2 = arr.myReduce(function (prev, item) {
console.log('prev : ', prev, ' --- ', 'item : ', item)
return prev + item
})
console.log(r2)
// var res = arr.reduce(function a(prev, item) {
// return prev + item
// }, 0)
// console.log(res)
/*
var res = arr.reduce(function a(prev, item) {
return prev + item
}, 0)
根据 arr 数组的结构, a 函数会被执行 5 次
+ 第一次: init === 0
=> prev: 0
=> item: 10
=> return: 0 + 10
+ 第二次:
=> prev: 10
=> item: 20
=> return 10 + 20
+ 第三次:
=> prev: 30
=> item: 30
=> return: 30 + 30
*/
/*
var res = arr.reduce(function a(prev, item) {
return prev + item
})
根据 arr 的数据结构和 reduce 的调用, a 函数会被执行 4 次
+ 第一次: init === 10
=> prev: 10
=> item: 20
=> return: 10 + 20
+ 第二次:
=> prev: 30
=> item: 30
=> return: 30 + 30
*/
案例9 封装范围内随机整数
- 封装函数, 能根据参数给出一个范围内的随机整数
// 1. 封装函数, 求 0 ~ 10 之间的随机整数
/*
概率问题:
放大十倍以后的取之范围 [0, 10)
+ 0 ~ 0.499 0
+ 0.5 ~ 1.499 1
+ 8.5 ~ 9.499 9
+ 9.5 ~ 9.999 10
*/
// function fn() {
// // 1. 拿到随机小数
// // 取值范围 [0, 1)
// var r1 = Math.random()
// // 2. 放大 10 倍
// // 取值范围 [0, 10)
// var r2 = r1 * 10
// // 3. 四舍五入
// var res = Math.round(r2)
// return res
// }
// function fn() {
// // 1. 拿到随机小数
// // 取值范围 [0, 1)
// var r1 = Math.random()
// // 2. 放大 10 倍
// // 取值范围 [0, 11)
// var r2 = r1 * (10 + 1)
// // 3. 取整
// // Math.ceil => 取整之前 -0.999 ~ 9.999
// // Math.floor => 取整之前 0 ~ 10.999
// var res = Math.floor(r2)
// return res
// }
// 2. 求 0 ~ 20 之间的随机整数
// function fn() {
// var r1 = Math.random()
// var r2 = r1 * (20 + 1)
// return Math.floor(r2)
// }
// 3. 求 10 ~ 30 之间的随机整数
// function fn() {
// // 1. 求 0 ~ 10 之间的随机整数
// var r1 = Math.floor(Math.random() * (20 + 1))
// // 2. 用结果 + 10
// return r1 + 10
// }
// 4. 求 min ~ max 之间的随机整数
// function fn(a, b) {
// // 0. 判断大小
// var min = Math.min(a, b)
// var max = Math.max(a, b)
// // 1. 求 0 ~ (max - min) 之间的随机整数
// var r1 = Math.floor(Math.random() * (max - min + 1))
// // 2. 加上 min
// return r1 + min
// }
// 函数的参数默认值
// 在设计形参的时候, 给形参添加一个默认值
// 使用的时候, 如果你没有传递实参, 那么就用默认值
// function fn(a = 255, b = 0) {
// return Math.floor(Math.random() * (Math.abs(a - b) + 1)) + Math.min(a, b)
// }
var obj = {}
for (var i = 0; i < 1000000; i++) {
var res = fn(17)
if (obj[res]) {
obj[res]++
} else {
obj[res] = 1
}
}
console.log(obj)
案例10 六位随机验证码
// function randomCode() {
// // 准备一个验证码可以出现的内容
// var str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
// // 准备一个变量接受结果
// var res = ''
// // 拿出随机的一位
// for (var i = 0; i < 6; i++) {
// var s = randomNum(str.length - 1)
// res += str[s]
// }
// // 返回 res
// return res
// }
// var res = randomCode()
// console.log(res)
// 需求2: 随机的 6 位不重复的验证码
// function randomCode() {
// // 准备一个验证码可以出现的内容
// var str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
// // 准备一个数组接受结果
// var res = []
// // 循环生成六个内容(不一定是六次)
// // 只要 res 的 length 小于 6, 就得再来一次
// while (res.length < 6) {
// // 向数组内添加一个内容
// var s = str[ randomNum(str.length - 1) ]
// // 一定要把 s 加进去吗 ?
// // 保证原始数组内没有内容的时候, 才添加
// if (res.indexOf(s) === -1) res.push(s)
// }
// // 制作返回值
// return res.join('')
// }
// var code = randomCode()
// console.log(code)
// 生成函数, 出现随机颜色字符串
function randomColor() {
// 组装一个随机数字的字符串
return `rgb(${ randomNum() }, ${ randomNum() }, ${ randomNum() })`
}
console.log(randomColor())
// document.body.style.backgroundColor = randomColor()