1.闭包
2.js执行机制
3.new发生了什么
4.防抖和节流
5.js原型和原型链
6.js作用域和作用域链
7.深拷贝、浅拷贝
8.Map Set
***************************** 升阶 ******************************
1.手写Promise
2.手写防抖(Debounce)和节流(Throttle)
3.手写深拷贝
4.手写EventEmitter
5.手写柯里化(2种)
***************************** 基础 ******************************
2-1.手写compose
2-2.手写reduce
2-3.手写instanceof ?
2-4.手写new?
2-4.手写aplly call bind?--作用: 指定上下文
2-4.手写继承(原型, class)?
一.手写Promise
class Kromise {
constructor(executor){
this.state = 'pendding'
this.value = undefined
this.reason = undefined
this.onResolvedStack = []
this.onRejectedStack = []
let resolve = value => {
this.state = 'fulfilled'
this.value = value
}
let reject = reason => {
this.state = 'rejected'
this.reason = reason
}
executor(resolve, reject)
}
static resolve(value) {
return new Kromise((resFn, rejFn) => {
resFn(value)
})
}
static reject(reason) {
return new Kromise((resFn, rejFn) => {
rejFn(reason)
})
}
static all(promises) {
return new Kromise((resFn, rejFn) => {
let reslovedResult = []
let count = 0
let state = false // 只要有一条报错,则返回这一条 ?? 使用state不是最优
for(let i = 0; i < promises.length; i++) {
if(!state) {
promises[i].then(res => { // 所有数据都resolve返回数组数据
count ++
reslovedResult[i] = res
if (count === promises.length) {
resFn(reslovedResult)
}
}, err => { // 有一条数据reject,返回该数据
state = true
rejFn(err)
})
}
}
})
}
static allSettled(promises) {
return new Kromise((resFn, rejFn) => {
let reslovedResult = []
for(let i = 0; i < promises.length; i++) {
promises[i].then(res => reslovedResult[i] = res, err => reslovedResult[i] = err)
}
resFn(reslovedResult)
})
}
static race(promises) { // 只要一个成功或失败,就返回该数据
return new Kromise((resFn, rejFn) => {
for(let i = 0; i < promises.length; i++) {
promises[i].then(resFn, rejFn)
return
}
})
}
then(resFn, rejFn) {
return new Kromise((resolve, reject) => {
if(this.state === 'fulfilled') {
resFn(this.value)
} else if(this.state === 'rejected') {
rejFn(this.reason)
} else {
this.onResolvedStack.push(() => resFn(this.value))
this.onRejectedStack.push(() => rejFn(this.reason))
}
})
}
}
// ==================================================
new Kromise(res => {
res(1)
new Kromise(res1 => res1(2)).then(val => console.log(val))
}).then(val => console.log(val))
Kromise.reject(22).then(res => {}, err => console.log(err))
const p1 = Kromise.resolve(11)
const p2 = Kromise.reject(22)
const p3 = Kromise.reject(33)
Kromise.race([p1,p2,p3]).then(res => console.log(res), err => console.log(err))
Kromise.all([p1,p2,p3]).then(res => console.log(res), err => console.log(err))
Kromise.allSettled([p1,p2,p3]).then(res => console.log(res), err => console.log(err))
二.手写防抖(Debouncing)和节流(Throttling)
const p = function(val,val2){console.log(val,val2)}
// 防抖---一次动作(打印)完成后,(200ms内不会生效, 本质第一次操作也是在200ms后执行)
function debounce(fn, delay) {
let timer
return function (...arg) {
if (timer) clearTimeout(timer)
setTimeout(() => fn.call(this, arg), delay)
}
}
// ===================================================
let d1 = throttle(p, 200)
d1(11,22)
d1(33)
setTimeout(() => d1(44), 100)
setTimeout(() => d1(55), 150)
setTimeout(() => d1(66), 150)
setTimeout(() => d1(77), 500)
// 节流---一段时间内仅执行一次操作
function throttle(fn, delay) {
let lastTime = 0
return function(...arg) {
let nowTime = new Date().getTime()
if(nowTime - lastTime > delay) {
// fn.call(this, arg)
fn.apply(this, arg)
}
lastTime = nowTime
}
}
// ==================================================
let p1 = throttle(p, 1000)
p1(1,2)
p1(2)
setTimeout(() => p1(3), 500)
setTimeout(() => p1(4), 2000)
三.手写深拷贝
function deepClone(obj) {
let target = Array.isArray(obj) ? [] : {} // 判断是数组还是对象
for(let i in obj) {
if(Object.prototype.hasOwnProperty.call(obj, i)) { // 判断是否是自身属性
if(typeof obj[i] === 'object') { // 判断子值类型
deepClone(obj[i])
} else {
target[i] = obj[i]
}
}
}
return target
}
// 对象
var p = { name: 'xiaoming' }
var p1 = deepClone(p)
p1.name = 'xiaowen'
console.log(p, p1)
// 数组
var p = [1,2,3,4,5]
var p1 = deepClone(p)
p1[1] = 1
console.log(p, p1)
四. 手写EventEmitter
// 最简版, 只考虑注册一次,若考虑多次注册就用数组
class KventEmitter {
constructor() {
this.handler = new Map()
}
on(eventName, fn) {
this.handler.set(eventName, fn)
}
emit(eventName, param) {
const fn = this.handler.get(eventName)
fn(param)
}
}
// ========================================
const event = new KventEmitter()
event.on('some_event', num => {
console.log('some_event 事件触发:'+num)
})
let num = 0
setInterval(() => {
event.emit('some_event' , num ++ )
}, 1000)
五. 手写柯里化(返回值是函数)
定义:通过把一个多参函数转换为一系列嵌套函数,每个函数依次接受一个参数
本质: 中间件处理数据
// A.
function currying(fn) {
let args = [] // 闭包变量
const cb = function(...arg) {
if(arg.length === 0) return fn.apply(this, args) // 执行请求
args = [...args, ...arg] //收集参数
return cb // 返回函数供传参
}
return cb // 第一次函数
}
const add = (...arg) => arg.reduce((a,b) => a+b)
const curry = currying(add)
// ===================================================
console.log(curry(1)(2,3)())
// B.理解
function curry(fn) {
// 保存预置参数, 去除fn参数
const presetArgs = [].slice.call(arguments, 1)
// 返回一个新函数
function curried (...arg) {
// 新函数调用时会继续传参
const allArgs = [...presetArgs, ...arg]
return curry.call(null, fn, ...allArgs)
}
// 重写toString
curried.toString = function() {
return fn.apply(null, presetArgs)
}
return curried
}
function dynamicAdd() {
return [...arguments].reduce((prev, curr) => {
return prev + curr
}, 0)
}
var add = curry(dynamicAdd);
console.log(add(1)(2,3).toString()) // 10
// B.精简
const add = (...args) => {
// 精髓1: 将args作为闭包变量, 收集所有参数
let _adder = (..._args) => {
args = [...args, ..._args]
return _adder
}
// 精髓2: 利用toString隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
_adder.toString = () => args.reduce((a, b) => a + b)
return _adder
}
// ===================================================
console.log(add(2,3)(1)(2).toString())
2-1. 手写compose
2-2. 手写reduce
Array.prototype.keduce = function (fn, preV) {
preV = preV ?? this[0]
for(let i = 1; i < this.length; i++) {
preV = fn(preV, this[i]) // preV是闭包中保存参数变量
}
return preV
}
// ===================================================
console.log([1,2,3,4].keduce((a,b) => a*b))
网友评论