1、promise
1.1 实现resolve和reject
class MyPromise {
// 构造方法
constructor(executor) {
// 初始化值
this.initValue()
// 初始化this指向
this.initBind()
try {
// 执行传进来的函数
executor(this.resolve, this.reject)
} catch (e) {
// 捕捉到错误直接执行reject
this.reject(e)
}
}
initBind() {
// 初始化this
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
initValue() {
// 初始化值
this.PromiseResult = null // 终值
this.PromiseState = 'pending' // 状态
}
resolve(value) {
// state是不可变的
if (this.PromiseState !== 'pending') return
// 如果执行resolve,状态变为fulfilled
this.PromiseState = 'fulfilled'
// 终值为传进来的值
this.PromiseResult = value
}
reject(reason) {
// state是不可变的
if (this.PromiseState !== 'pending') return
// 如果执行reject,状态变为rejected
this.PromiseState = 'rejected'
// 终值为传进来的reason
this.PromiseResult = reason
}
}
测试代码:
const test3 = new MyPromise((resolve, reject) => {
throw('fail')
})
console.log(test3) // MyPromise { PromiseState: 'rejected', PromiseResult: 'fail' }
1.2 实现then方法
then(onFulfilled, onRejected) {
// 接收两个回调 onFulfilled, onRejected
// 参数校验,确保一定是函数
onFulfilled = typeof onFulfilled === 'function' ?
onFulfilled : val => val
onRejected = typeof onRejected === 'function' ?
onRejected : reason => { throw reason }
if (this.PromiseState === 'fulfilled') {
// 如果当前为成功状态,执行第一个回调
onFulfilled(this.PromiseResult)
} else if (this.PromiseState === 'rejected') {
// 如果当前为失败状态,执行第二哥回调
onRejected(this.PromiseResult)
}
}
测试代码:
// 输出 ”success“
const test = new MyPromise((resolve, reject) => {
resolve('success')
}).then(res => console.log(res), err => console.log(err))
2、call
2.1 实现思路
call() :在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。
let foo = {
value: 1
};
function bar() {
console.log(this.value);
}
bar.call(foo); // 1
上述调用注意两点:
1. call 改变了 this 的指向,指向到 foo;
2. bar 函数执行了;
上述方式等同于:
let foo = {
value: 1,
bar: function() {
console.log(this.value)
}
};
foo.bar(); // 1
这个时候 this 就指向了 foo,但是这样却给 foo 对象本身添加了一个属性,所以们用 delete 再删除它即可。
所以我们模拟的步骤可以分为:
-
将函数设为对象的属性;
-
执行该函数;
-
删除该函数;
// 第一步
// fn 是对象的属性名,反正最后也要删除它,所以起什么都可以。
foo.fn = bar
// 第二步
foo.fn()
// 第三步
delete foo.fn
2.2 实现
2.2.1 指定this
2.2.2 指定参数
2.2.3 this 参数可以传 null,当为 null 的时候,视为指向 window
// 第三版
Function.prototype.call2 = function (context) {
var context = context || window;
context.fn = this;
let arg = [...arguments].slice(1)
let result = context.fn(...arg)
delete context.fn
return result
}
// 测试一下
var value = 2;
var obj = {
value: 1
}
function bar(name, age) {
console.log(this.value);
return {
value: this.value,
name: name,
age: age
}
}
bar.call2(null); // 2
console.log(bar.call2(obj, 'kevin', 18));
// 1
// Object {
// value: 1,
// name: 'kevin',
// age: 18
// }
3、apply
apply 的实现跟 call 类似,只是入参不一样,apply为数组
Function.prototype.apply = function (context, arr) {
var context = Object(context) || window;
context.fn = this;
var result;
if (!arr) {
result = context.fn();
}
else {
result = context.fn(...arr)
}
delete context.fn
return result;
}
4、bind
5、debounce > 防抖
防抖: 如果在一定的时间内 (n) 频繁的触发,只会执行最后一次
5.1 js实现
function debounce(func, ms) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args)
}, ms);
}
}
5.1 hooks实现
import { useEffect, useRef } from 'react'
const useDebounce = (fn, ms = 30, deps = []) => {
let timeout = useRef()
useEffect(() => {
if (timeout.current) clearTimeout(timeout.current)
timeout.current = setTimeout(() => {
fn()
}, ms)
}, deps)
const cancel = () => { // 防止内存泄露
clearTimeout(timeout.current)
timeout = null
}
return [cancel]
}
export default useDebounce
// 实际使用
import { useDebounce } from 'hooks'
const Home = (props) => {
const [a, setA] = useState(0)
const [b, setB] = useState(0)
const [cancel] = useDebounce(() => {
setB(a)
}, 2000, [a])
const changeIpt = (e) => {
setA(e.target.value)
}
return <div>
<input type="text" onChange={changeIpt} />
{ b } { a }
</div>
}
6、throttle > 节流
节流:每一次触发的时候,会记录与首次触发的一个时间差,如果时间差大于传入的这个时间,则重新计时
6.1 js实现
function throttle(func, ms) {
let previous = 0;
return function() {
let now = Date.now();
let context = this;
let args = arguments;
if (now - previous > ms) {
func.apply(context, args);
previous = now;
}
}
}
6.2 hooks实现
mport { useEffect, useRef, useState } from 'react'
const useThrottle = (fn, ms = 30, deps = []) => {
let previous = useRef(0)
let [time, setTime] = useState(ms)
useEffect(() => {
let now = Date.now();
if (now - previous.current > time) {
fn();
previous.current = now;
}
}, deps)
const cancel = () => {
setTime(0)
}
return [cancel]
}
export default useThrottle