手写promise
class MyPromise {
static PENDING = 'pending'
static FULFILLED = 'fulfilled'
static REJECTED = 'rejected'
constructor(surper) {
this.value = null
this.state = MyPromise.PENDING
this.callbacks = []
try {
surper(this.resolve, this.reject)
} catch (err) {
this.reject(err)
}
}
resolve = (value) => {
if (this.state !== MyPromise.PENDING) return
this.state = MyPromise.FULFILLED
this.value = value
setTimeout(() => {
this.callbacks.forEach(item => {
item.reso(value)
})
});
}
reject = (reason) => {
if (this.state !== MyPromise.PENDING) return
this.state = MyPromise.REJECTED
this.value = reason
setTimeout(() => {
this.callbacks.forEach(item => {
item.reje(reason)
})
});
}
then = (reso, reje) => {
if (typeof reso !== 'function') {
reso = () => this.valeu
}
if (typeof reje !== 'function') {
reje = () => this.valeu
}
return new MyPromise((resolve, reject) => {
if (this.state === MyPromise.PENDING) {
this.callbacks.push({
reso: value => {
try {
const result = reso(value)
resolve(result)
} catch (err) {
reje(err)
}
},
reje: value => {
try {
const result = reje(value)
resolve(result)
} catch (err) {
reje(err)
}
},
})
}
if (this.state === MyPromise.FULFILLED) {
setTimeout(() => {
try {
const result = reso(this.value)
resolve(result)
} catch (err) {
reject(err)
}
})
}
if (this.state === MyPromise.REJECTED) {
setTimeout(() => {
try {
const result = reje(this.value)
resolve(result)
} catch (err) {
reject(err)
}
})
}
})
}
}
手写Promise.race
Promise.myRace = function (promises) {
return new Promise((resolve, reject) => {
if (typeof promises[Symbol.iterator] !== 'function') {
reject('TypeError: promises is not iterable')
}
for (const item of promises) {
Promise.resolve(item).then(resolve, reject)
}
})
}
function p1() {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 1)
})
}
function p2() {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 2)
})
}
Promise.myRace([p1(), p2()]).then((res) => {
console.log(res)
})
手写Promise.any
Promise.myAny = function (promises) {
return new Promise((resolve, reject) => {
if (typeof promises[Symbol.iterator] !== 'function') {
reject('TypeError: promises is not iterable')
}
const len = promises.length
let count = 0
for (let i = 0; i < len; i++) {
Promise.resolve(promises[i]).then(resolve, (err) => {
count += 1
if (count === promises.length) {
reject(new Error('所有 promise 都失败'))
}
})
}
})
}
function p1() {
return new Promise((resolve, reject) => {
setTimeout(reject, 1000, 1)
})
}
function p2() {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 2)
})
}
Promise.myAny([p1(), p2()]).then((res) => {
console.log(res)
})
手写Promise.all
Promise.myAll = function (promises) {
return new Promise((resolve, reject) => {
if (typeof promises[Symbol.iterator] !== 'function') {
reject('TypeError: promises is not iterable')
}
if (promises.length === 0) {
resolve([])
} else {
const res = []
const len = promises.length
let count = 0
for (let i = 0; i < len; i++) {
Promise.resolve(promises[i])
.then((data) => {
res[i] = data
count += 1
if (count === len) {
resolve(res)
}
})
.catch((err) => {
reject(err)
})
}
}
})
}
function p1() {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 1)
})
}
function p2() {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 2)
})
}
Promise.myAll([p1(), p2()]).then(res => {
console.log(res)
})
手写map
function myMap (fn,content) {
let arr = Array.prototype.slice.call(this)
let newArr = []
for(let i = 0
// 防止稀疏数组
if(!arr.hasOwnProperty(i)) continue
newArr[i] = fn.call(content,arr[i],i,this)
}
return newArr
}
Array.prototype.myMap = myMap
console.log([1,2,3].myMap(d => d * 2))
手写filter
function myFilter (fn,content) {
let arr = Array.prototype.slice.call(this);
let newArr = [];
for(let i = 0 ; i<arr.length;i++) {
if(!arr.hasOwnProperty(i)) continue;
fn.call(content,arr[i],i,this) && newArr.push(arr[i])
}
return newArr
}
Array.prototype.myFilter = myFilter
console.log([1,2,3].myFilter((d,i,arr) => {
console.log(d,i,arr)
return d === 2
}))
手写 some
function mySome (fn,content) {
let arr = Array.prototype.slice.call(this);
let newArr = [];
for(let i = 0 ; i<arr.length;i++) {
if(!arr.hasOwnProperty(i)) continue;
if(fn.call(content,arr[i],i,this)) return true
}
return false
}
Array.prototype.mySome = mySome
console.log([1,2,3].mySome((d,i,arr) => {
return d === 3
}))
手写 every
function myEvery (fn,content) {
let arr = Array.prototype.slice.call(this)
let newArr = []
for(let i = 0
// 防止稀疏数组
if(!arr.hasOwnProperty(i)) continue
if(fn.call(content,arr[i],i,this)) {
newArr.push(arr[i])
}
}
return newArr.length === arr.length
}
Array.prototype.myEvery = myEvery
console.log([1,2,3].myEvery((d,i,arr) => {
return d < 3
}))
手写 find
function myFind (fn,content) {
let arr = Array.prototype.slice.call(this);
let current = null;
for(let i = 0 ; i<arr.length;i++) {
if(!arr.hasOwnProperty(i)) continue;
if(fn.call(content,arr[i],i,this) && !current) {
current = arr[i];
break;
}
}
return current
}
Array.prototype.myFind = myFind
console.log([1,2,3].myFind((d,i,arr) => {
return d < 4 && d !==1
}))
手写 findIndex
function myFindIndex (fn,content) {
let arr = Array.prototype.slice.call(this);
let current = null;
for(let i = 0 ; i<arr.length;i++) {
if(!arr.hasOwnProperty(i)) continue;
if(fn.call(content,arr[i],i,this) && !current) {
current = i
break;
}
}
return current
}
Array.prototype.myFindIndex = myFindIndex
console.log([1,2,3].myFindIndex((d,i,arr) => {
return d < 4 && d !==1
}))
手写 new
- 创建一个空对象
- 这个新对象 原型 的连接
- 执行构造函数方法,属性和方法指向创建的对象
- 如果构造函数中没有返回其它对象,那么返回this,即创建的这个的新对象,否则,返回构造函数中返回的对象。
function myNew(){
let targetObj={}
let [constructor,...args]=[...arguments]
targetObj.__proto__=constructor.prototype
let result =constructor.apply(targetObj,args)
if(result&&(typeof (result)==='object'||typeof (result)==='function')){
return result
}
return targetObj
}
手写 call
- 不传入第一个参数,那么上下文默认为 window
- 改变了 this 指向,让新的对象可以执行该函数,并能接受参数
Function.prototype.myCall = function (content) {
if(typeof this !== 'function') {
throw new TypeError("myCall Error")
}
content = content || window;
content.fn = this;
const arg = [...arguments].slice(1);
const result = content.fn(...arg);
delete content.fn;
return result;
}
- context 为可选参数,如果不传的话默认上下文为 window
- 给 context 创建一个 fn 属性,并将值设置为需要调用的函数
- 因为 call 可以传入多个参数作为调用函数的参数,所以需要将参数剥离出来
- 然后调用函数并将对象上的函数删除
手写 apply
Function.prototype.myApply = function (content) {
if(typeof this !== 'function') {
throw new TypeError("myCall Error")
}
content = content || window;
content.fn = this;
let result = arguments[1] ?content.fn(...arguments[1]) : content.fn()
delete content.fn;
return result;
}
手写 bind
Function.prototype.myBind = function (context) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
const _this = this
const args = [...arguments].slice(1)
return function F() {
if (this instanceof F) {
return new _this(...args, ...arguments)
}
return _this.apply(context, args.concat(...arguments))
}
}
- bind 返回了一个函数,对于函数来说有两种方式调用,一种是直接调用,一种是通过 new 的方式,我们先来说直接调用的方式
- 对于直接调用来说,这里选择了 apply 的方式实现,但是对于参数需要注意以下情况:因为 bind 可以实现类似这样的代码 f.bind(obj, 1)(2),所以我们需要将两边的参数拼接起来,于是就有了这样的实现 args.concat(...arguments)
- 最后来说通过 new 的方式,在之前的章节中我们学习过如何判断 this,对于 new 的情况来说,不会被任何方式改变 this,所以对于这种情况我们需要忽略传入的 this
手写 instanceof
function myInstanceof(left, right) {
let prototype = right.prototype
left = left.__proto__
while (true) {
if (left === null || left === undefined)
return false
if (prototype === left)
return true
left = left.__proto__
}
}
- 首先获取类型的原型
- 然后获得对象的原型
- 然后一直循环判断对象的原型是否等于类型的原型,直到对象原型为 null,因为原型链最终为 null
手写防抖
const debounce = (fn: any, t: number = 2000, ...rest) => {
let timer: any;
return function () {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, rest);
}, t)
}
}
手写节流
const throttle = (fn: Function, t: number = 2000, ...rest) => {
let t1 = 0
return function () {
let t2 = new Date()
if (t2 - t1 > t) {
fn.apply(this, rest)
t1 = t2
}
}
}