Promise 的其他方法
- 总代码:
function fn() {
const p = new Promise(function (reslove, reject) {
const timer = Math.ceil(Math.random() * 3000) + 2000
setTimeout(() => {
if (timer > 3500) {
reject('失败')
} else {
reslove('成功')
}
}, timer)
})
return p
}
- promise实例化对象 还有一个方法
- finally-----不管成功失败都会执行
-
/** * promise 实例化对象 还有一个方法 */ fn().then(res => { console.log('成功了: ', res) }).catch(res => { console.log('失败了: ', res) }).finally(res => { console.log('不管成功还是失败, 一定会执行, 然后我现在把 loadding 图片关闭') })
-
Promise构造函数上也有一些方法
-
all接受一个数组,数组内可以传递多个promise对象
- all方法的状态取决数组内部的promise对象的状态
- 如果都成功,all方法也是成功
- 如果有一个失败,all方法就是失败
-
Promise.all([fn(), fn(), fn()]) .then(res => { console.log('如果我输出, 代表所有 promise 对象都是成功状态') }) .catch(res => { console.log('如果我输出, 代表最少有一个 promise 状态为失败状态') })
-
race接受一个数组,数组内可以传递多个promise对象
-
race方法的状态取决于数组内部的promise对象中第一个结束的
-
如果第一个结束时是成功,race就是成功
-
如果第一个结束时是失败,race就是失败
-
Promise.race([fn(), fn(), fn()]) .then(res => { console.log('如果我执行, 代表 数组内第一个结束的 promise状态为成功') }) .catch(res => { console.log('如果我执行, 代表 数组内第一个结束的 promise状态为失败') })
-
allSettled接受一个数组,数组内可以传递多个promise
- 他只执行 .then,接收到的参数是一个数组形式的,内部元素为对应的promise的状态
-
Promise.allSettled([fn(), fn(), fn(), fn()]) .then(res => { console.log(res) })
-
-
- 强行返回一个成状态
-
Promise.resolve() // 4. 强行帮我们返回一个成功状态的 promise 对象 .then(res => { console.log('成功') }).catch(res => { console.log('失败') })
- 强行返回一个失败状态
-
Promise.reject() // 5. 强行帮我们返回一个失败状态的 promise 对象 .then(res => { console.log('成功') }).catch(res => { console.log('失败') })
数组扁平化
const arr = [1, 2, 3, [4, 5, [6, 7, [8, 9]]]]
-
面试版:
console.log('原始数据: ', arr) // 面试版写法 function flat(origin) { const newArr = [] // 数组扁平化核心函数 function inner(innerOrigin) { innerOrigin.forEach(item => { if (Object.prototype.toString.call(item) === '[object Array]') { inner(item) } else { newArr.push(item) } }) } // 调用核心函数, 并将原始数组传递进去 inner(origin) return newArr } const newArr = flat(arr) -
toString----将数组内的所有成员转换为字符串并通过逗号合并在一起----这种方式处理数字或者字符串
const newArr = arr.toString().split(',') console.log(newArr[3] - 0) -
flat( )------数组给我们提供的扁平化的方法-----需要接受一个参数,代表拆几层,默认不传递为1
Infinity: 在JS中代表正无穷
-Infinity: 代表负无穷
const newArr = arr.flat(Infinity) console.log('扁平化之后的新数组: ', newArr) -
最后的结果:
arr === [1,2,3,4,5,6,7,8,9]
设计模式
- 设计模式:为了实现某一类功能的一个简洁优化的写法
- 单例模式:一个构造函数(类),一生只能有一个实例化对象
- 需求:一个构造函数,在实例化对象时,判断是否 为第一次实例化
- ------如果是第一次,创建一个实例化对象,然后返回
- --------如果不是第一次,想办法拿到第一次的实例化对象,然后返回
- 解决:拿一个变量,初始值给一个nul
- l-------在实例化对象时,第一次实例化,直接将实例化赋值给变量,然后将变量返回
- -------后续再实例化的时候,直接返回刚才的变量
-
class Dialog { constructor() { console.log('创建一个 弹出框 插入到 页面中, 类型为: ') } } // 单例模式核心代码(有bug) let instance = null function newDialog() { if (instance === null) { instance = new Dialog() } return instance } const n1 = newDialog() console.log(n1) const n2 = newDialog() console.log(n2) - 总代码:
-
class Dialog { constructor(title) { console.log('创建一个 弹出框 插入到 页面中, 类型为: ') this.title = title } } let instance = null function newDialog(type) { if (instance === null) { instance = new Dialog(type) } return instance } - 问题1:全局多了一个变量instance
- 解决问题1:通过闭包解决
-
class Dialog { constructor(title) { console.log('创建一个 弹出框 插入到 页面中, 类型为: ') this.title = title } }
// 1. 通过 闭包, 解决问题1 function fn(type) { let instance = null return function newDialog() {
if (instance === null) {
instance = new Dialog(type)
}
return instance
}
}
* 利用自执行函数优化
* ```javascript
const newDialog = (function fn() {
let instance = null
return function inner(type) {
if (instance === null) {
instance = new Dialog(type)
}
return instance
}
})()
- 问题2:传递多个参数 无法生效
- 解决:
-
class Dialog { constructor() { console.log('创建一个 弹出框 插入到 页面中, 类型为: ') this.title = '' } // 每次需要 给 title 赋值, 直接调用这个方法即可 init (title) { this.title = title console.log('当前 title 的值为: ', title) } } const newDialog = (function fn() { let instance = null return function inner(type) { if (instance === null) { instance = new Dialog() } instance.init(type) return instance } })()
- 问题3:构造函数的类和实际使用创建的函数不是一个名
- 解决:
-
const Dialog = (function fn() { let instance = null class Dialog { constructor() { console.log('创建一个 弹出框 插入到 页面中, 类型为: ') this.title = '' } // 每次需要 给 title 赋值, 直接调用这个方法即可 init(title) { this.title = title console.log('当前 title 的值为: ', title) } } return function inner(type) { // 1. 自动帮我们创建一个 对象, 自动帮我们把函数内部的 this 指向这个新建对象 // 2. 手动往对象上添加属性 // 3. 自动返回一个对象 // 4. 构造函数内部不要写 return, 返回一个 基本数据类型, 写了和没写一样, // 如果返回一个 引用数据类型, 写了 构造函数就没用了 if (instance === null) { instance = new Dialog() } instance.init(type) return instance } })() // 单例模式, 一般不建议写 new const n1 = Dialog('警告') const n2 = new Dialog('文本') const n3 = new Dialog('红色警告')
- 策略模式
- 核心:减少过多的if...else...
- 处理:有一个数据结构 内部存储着各种折扣对应的计算总价方式
- 基础板
-
const price = (function () { // 该变量内部 存储 对应的折扣与总价计算方式 let priceList = { '80%': total => total * 0.8, '70%': total => total * 0.7, } return function inner(type, total) { // console.log('inner 函数开始执行, 计算商品总价') // console.log(type) // console.log(priceList[type]) return priceList[type](total) } })() // console.log(price) let newPrice1 = price('80%', 1000) // let newPrice2 = price('70%', 1000) console.log(newPrice1) // console.log(newPrice2)
- 进阶版------写法1:
-
const price = (function () { let priceList = { '80%': total => total * 0.8, '70%': total => total * 0.7, } // 写法1 必须是 执行了 inner 函数, 才能够给 这个函数上 添加 对应的方法 return function inner(type, total) { inner.add = (key, value) => { // 这个函数负责 向 priceList 内部 添加 新的 key priceList[key] = value } inner.sub = (key) => { priceList[key] = null // delete priceList[key] } inner.getList = () => { return priceList } return priceList[type](total) }
- 进阶版-----写法2:
-
const price = (function () { let priceList = { '80%': total => total * 0.8, '70%': total => total * 0.7, } // 写法2 function inner(type, total) { return priceList[type](total) } inner.add = (key, value) => { // 这个函数负责 向 priceList 内部 添加 新的 key priceList[key] = value } inner.sub = (key) => { priceList[key] = null // delete priceList[key] } inner.getList = () => { return priceList } return inner })() let newPrice1 = price('80%', 1000) console.log(newPrice1) price.add('60%', total => total * 0.6) price.sub('60%') // let newPrice2 = price('60%', 1000) // console.log(newPrice2) let list = price.getList() console.log(list) // 所有的引用数据类型(对象 数组 函数), 都可以当作 对象去使用 // function fn(a, b, c, d) {} // // console.dir(fn) // fn.abc = 999 // console.dir(fn)
-
发布订阅模式
-
并不是1对1,而是1对多
-
class observer { constructor(name) { this.name = name // 模拟一个店员(不重要) // 店员的记录手册 this.message = {} } // 原型 add(type, fn) { if (this.message[type] === undefined) { this.message[type] = [] } this.message[type].push(fn) } tri(type) { // 调用这个方法, 通知对应的 人员 来购买 // console.log(type) // console.log(this.message[type]) this.message[type].forEach(item => { // console.log(item) item() }) } remove(type, fn) { // console.log(type, fn) // console.log(this.message[type], fn) this.message[type] = this.message[type].filter(item => item !== fn) } } const res = new observer('小方') console.log('初始数据: ', res) const fnA = () => { console.log('我是张三, 我想购买这本书') } const fnB = () => { console.log('我是李四, 我想购买这本书') } const fnC = () => { console.log('我是王五, 我想购买这本书') } // 新增(留下联系方式) res.add('JS从入门到入土', fnA) res.add('JS从入门到入土', fnB) res.add('颈椎病的预防', fnC) // 书本到了, 通知对应的预约者, 前来购买 res.tri('颈椎病的预防') // 某人, 取消预约一本书 res.remove('JS从入门到入土', fnA)